Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: В чем практический смысл отличий регулярных и инжектированных каналов АЦП в STM32F103?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Salamander
Как я понял из даташита - у регулярных каналов только один общий регистр, где хранится результат преобразования, а у инжектирвоанны, хоть их и всего 4 - свои собственные.
Мне с трудом верится, что разработчики поскупились на лишние регистры, более того, затеяли мороку с инжектированными каналами. Ведь куда было бы проще - 16 каналов, 16 регистров.
Возникает мысль, что в создании инжектированных каналов есть какой-то сакральный смысл? Какой?

Опять-таки, если я настроил 2 регулярных канала, в режиме сканирования и в какой-то определенный момент я полез прочитать результат измерения, как мне понять с какого канал он пришел? Или с кучей регулярных каналов можно работать только через DMA ?

Сергей Борщ
Цитата(Salamander @ Feb 22 2015, 22:50) *
Возникает мысль, что в создании инжектированных каналов есть какой-то сакральный смысл? Какой?
В том, что их преобразование происходит сразу по сигналу начала преобразования и может прерывать преобразование регулярных каналов. Прерванное преобразование регулярного канала производится заново после окончания инжектированного.
Цитата(Salamander @ Feb 22 2015, 22:50) *
Опять-таки, если я настроил 2 регулярных канала, в режиме сканирования и в какой-то определенный момент я полез прочитать результат измерения, как мне понять с какого канал он пришел? Или с кучей регулярных каналов можно работать только через DMA ?
Понять никак. Или ПДП, или после каждого преобразования вычитывать результат и вести свой счетчик текущего канала. ПДП удобнее.
ViKo
Запускайте инжектированные преобразования регулярно, и всегда будете иметь результаты каждый в своем регистре.
Salamander
Вот что я нашел в мануалах
CODE

STM32F10x Standard Peripherals Firmware Library
Main Page
Related Pages
Modules
Data Structures
Files
Directories
File List
Globals
STM32F10x_StdPeriph_Lib_V3.5.0 Project STM32F10x_StdPeriph_Examples ADC ADC1_DMA
STM32F10x_StdPeriph_Examples/ADC/ADC1_DMA/main.c
Go to the documentation of this file.
00001 /**
00002 ******************************************************************************
00003 * @file ADC/ADC1_DMA/main.c
00004 * @author MCD Application Team
00005 * @version V3.5.0
00006 * @date 08-April-2011
00007 * @brief Main program body
00008 ******************************************************************************
00009 * @attention
00010 *
00011 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
00012 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
00013 * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
00014 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
00015 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
00016 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
00017 *
00018 * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
00019 ******************************************************************************
00020 */
00021
00022 /* Includes ------------------------------------------------------------------*/
00023 #include "stm32f10x.h"
00024
00025 /** @addtogroup STM32F10x_StdPeriph_Examples
00026 * @{
00027 */
00028
00029 /** @addtogroup ADC_ADC1_DMA
00030 * @{
00031 */
00032
00033
00034 /* Private typedef -----------------------------------------------------------*/
00035 /* Private define ------------------------------------------------------------*/
00036 #define ADC1_DR_Address ((uint32_t)0x4001244C)
00037
00038 /* Private macro -------------------------------------------------------------*/
00039 /* Private variables ---------------------------------------------------------*/
00040 ADC_InitTypeDef ADC_InitStructure;
00041 DMA_InitTypeDef DMA_InitStructure;
00042 __IO uint16_t ADCConvertedValue;
00043
00044 /* Private function prototypes -----------------------------------------------*/
00045 void RCC_Configuration(void);
00046 void GPIO_Configuration(void);
00047
00048 /* Private functions ---------------------------------------------------------*/
00049
00050 /**
00051 * @brief Main program
00052 * @param None
00053 * @retval None
00054 */
00055 int main(void)
00056 {
00057 /*!< At this stage the microcontroller clock setting is already configured,
00058 this is done through SystemInit() function which is called from startup
00059 file (startup_stm32f10x_xx.s) before to branch to application main.
00060 To reconfigure the default setting of SystemInit() function, refer to
00061 system_stm32f10x.c file
00062 */
00063
00064 /* System clocks configuration ---------------------------------------------*/
00065 RCC_Configuration();
00066
00067 /* GPIO configuration ------------------------------------------------------*/
00068 GPIO_Configuration();
00069
00070 /* DMA1 channel1 configuration ----------------------------------------------*/
00071 DMA_DeInit(DMA1_Channel1);
00072 DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
00073 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;
00074 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
00075 DMA_InitStructure.DMA_BufferSize = 1;
00076 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
00077 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
00078 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
00079 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
00080 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
00081 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
00082 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
00083 DMA_Init(DMA1_Channel1, &DMA_InitStructure);
00084
00085 /* Enable DMA1 channel1 */
00086 DMA_Cmd(DMA1_Channel1, ENABLE);
00087
00088 /* ADC1 configuration ------------------------------------------------------*/
00089 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
00090 ADC_InitStructure.ADC_ScanConvMode = ENABLE;
00091 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
00092 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
00093 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
00094 ADC_InitStructure.ADC_NbrOfChannel = 1;
00095 ADC_Init(ADC1, &ADC_InitStructure);
00096
00097 /* ADC1 regular channel14 configuration */
00098 ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);
00099
00100 /* Enable ADC1 DMA */
00101 ADC_DMACmd(ADC1, ENABLE);
00102
00103 /* Enable ADC1 */
00104 ADC_Cmd(ADC1, ENABLE);
00105
00106 /* Enable ADC1 reset calibration register */
00107 ADC_ResetCalibration(ADC1);
00108 /* Check the end of ADC1 reset calibration register */
00109 while(ADC_GetResetCalibrationStatus(ADC1));
00110
00111 /* Start ADC1 calibration */
00112 ADC_StartCalibration(ADC1);
00113 /* Check the end of ADC1 calibration */
00114 while(ADC_GetCalibrationStatus(ADC1));
00115
00116 /* Start ADC1 Software Conversion */
00117 ADC_SoftwareStartConvCmd(ADC1, ENABLE);
00118
00119 while (1)
00120 {
00121 }
00122 }
00123
00124 /**
00125 * @brief Configures the different system clocks.
00126 * @param None
00127 * @retval None
00128 */
00129 void RCC_Configuration(void)
00130 {
00131 #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
00132 /* ADCCLK = PCLK2/2 */
00133 RCC_ADCCLKConfig(RCC_PCLK2_Div2);
00134 #else
00135 /* ADCCLK = PCLK2/4 */
00136 RCC_ADCCLKConfig(RCC_PCLK2_Div4);
00137 #endif
00138 /* Enable peripheral clocks ------------------------------------------------*/
00139 /* Enable DMA1 clock */
00140 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
00141
00142 /* Enable ADC1 and GPIOC clock */
00143 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
00144 }
00145
00146 /**
00147 * @brief Configures the different GPIO ports.
00148 * @param None
00149 * @retval None
00150 */
00151 void GPIO_Configuration(void)
00152 {
00153 GPIO_InitTypeDef GPIO_InitStructure;
00154
00155 /* Configure PC.04 (ADC Channel14) as analog input -------------------------*/
00156 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
00157 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
00158 GPIO_Init(GPIOC, &GPIO_InitStructure);
00159 }
00160
00161 #ifdef USE_FULL_ASSERT
00162
00163 /**
00164 * @brief Reports the name of the source file and the source line number
00165 * where the assert_param error has occurred.
00166 * @param file: pointer to the source file name
00167 * @param line: assert_param error line source number
00168 * @retval None
00169 */
00170 void assert_failed(uint8_t* file, uint32_t line)
00171 {
00172 /* User can add his own implementation to report the file name and line number,
00173 ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
00174
00175 /* Infinite loop */
00176 while (1)
00177 {
00178 }
00179 }
00180
00181 #endif
00182
00183 /**
00184 * @}
00185 */
00186
00187 /**
00188 * @}
00189 */
00190
00191 /******************* © COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/



For complete documentation on STM32(CORTEX M3) 32-bit Microcontrollers platform visit www.st.com/STM32




Как, положим добавить туда еще один канал, я знаю.
Но мне непонятны две вещи
1. Как прочесть данные из определенного канала?
2. Как при срабатывании Analog Watchdog понять какой канал вызвал прерывание и нужен ли DMA, если мне не интересны данные, а важен сам факт срабатывания аналоговой собачки?
Сергей Борщ
Цитата(Salamander @ Feb 23 2015, 18:51) *
1. Как прочесть данные из определенного канала?
Пользование библиотеками не отменяет необходимости чтения документации.
Цитата(Salamander @ Feb 23 2015, 18:51) *
2. Как при срабатывании Analog Watchdog понять какой канал вызвал прерывание
Прочитать результаты преобразования каждого канала и сравнить с вашими пределами. Аппаратного указателя на сработавший канал не предусмотрено.

Цитата(Salamander @ Feb 23 2015, 18:51) *
и нужен ли DMA, если мне не интересны данные, а важен сам факт срабатывания аналоговой собачки?
В свете предыдущего ответа - да.
alux
Цитата(Salamander @ Feb 23 2015, 19:51) *
1. Как прочесть данные из определенного канала?

При использовании регулярных каналов данные складываются последовательно с каждого канала в определенный массив. Достаточно объявить этот массив как двумерный:
CODE
/**
* Configuration:
* Defines the size of the ADC sample array. Defining a larger value here will significantly increase
* the amount of static RAM usage, but more values will be used for averaging, leading to lower noise.
*/
#define ADCNUMCHAN 5 /* Number of channel */
#define ADCNUMSAMPLES 16 /* Number of samples */
#define ADCCONVERTEDVALUES_BUFFER_SIZE ((uint32_t)(ADCNUMCHAN*ADCNUMSAMPLES))
/* Size of array ADCxConvertedValues[num_chan * num_samples]: set to ADC sequencer number of ranks converted, to have a rank in each address */
/* Array containing ADC conversions results */
__IO uint16_t ADCxConvertedValues[ADCNUMSAMPLES][ADCNUMCHAN];
--------------------
// -- Enables ADC DMA request
if (HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&ADCxConvertedValues, ADCCONVERTEDVALUES_BUFFER_SIZE) != HAL_OK)
{
Error_Handler();
}

... и в обработчике прерывания ADC-DMA всей последовательности:
CODE
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
uint32_t accum = 0;

for (uint8_t ch = 0; ch < ADCNUMCHAN; ch++)
{
for (uint16_t i = 0; i < ADCNUMSAMPLES; i++)
{
accum += ADCxConvertedValues[i][ch];
}
Value.codeADC[ch] = accum / ADCNUMSAMPLES;
accum = 0;}
Сергей Борщ
Цитата(alux @ Feb 26 2015, 05:23) *
Достаточно объявить этот массив как двумерный:
Бррр... И помнить, какой канал в каком элементе вложенного массива?
Код
    struct regular_result
    {
        sample_t DTMF;
        sample_t Audio;
        sample_t RSSI;
    };

    typedef regular_result buffer[ADC_BUFFER_SIZE];
    buffer Buffer[2];     // twice the buffer size, to get DMA "half ready" int in the middle

    adc::regular_result const * ADC_data = (DMA1->ISR & DMA_ISR_HTIF1) ? Buffer[0] : Buffer[1];  // это для примера. Разумеется, флаг анализируется в прерывании
    for(uint_fast8_t i = 0; i < adc::ADC_BUFFER_SIZE; ++i)
    {
          MM24_demod.set_rssi(ADC_data[i]->RSSI);
          CID_receiver.dtmf_process(ADC_data[i]->DTMF);
          MM24_demod.sample(ADC_data[i]->Audio);
    }
alux
Так результаты измерений каждого канала ложатся в буфер согласно RANK. Для серии STM32F0 Rank есть номер канала, и это нельзя изменить. В серии F4 "тасовать" каналы можно в любом порядке, присвоив определенному каналу уникальный Rank. По-моему, с двумерным массивом проще не придумаешь. Не вижу проблемы...
Salamander
Эх... с инжектированными каналами я разобрался. И с аналоговой собачкой тоже.
и озвученный уважаемым Борщом принцип
Цитата
Прочитать результаты преобразования каждого канала и сравнить с вашими пределами. Аппаратного указателя на сработавший канал не предусмотрено.


реализовал.

Но уперся в интересную штуку.... Смотрите, мне нужно анализировать 3 канала, ловить импульсы. С одним каналом получилось - я поставил пределы от 0 до 2048, соответственно ловлю фронт. А поймав, чтобы собакотаймер не гавкал каждый такт, перевожу пределы в диапазон от 2048 до 4096. Соответственно, после этого я ловлю только спад.

Но... если у меня 3 канала и на каждом независимо идущие импульсы.... Да, я поймав прерывание могу проанализировать с какого канала оно пришло, как посоветовал Борщ. Но если я изменю пределы, то это повлияет на анализ импульсов других каналов.
Решаема ли эта задача средствами STM32 ?
SSerge
Цитата(Salamander @ Feb 26 2015, 22:48) *
Решаема ли эта задача средствами STM32 ?

Если ничего не получается попробуйте применить DMA.
На STM32 это часто помогает wink.gif

Можно попробовать запускать сразу два канала DMA, один будет как обычно вычитывать результат преобразования из DR, а второй пересылать в регистры HTR и LTR пороги для следующего канала.
Salamander
Это эквивалентно тому, как если бы я измерив один импульс, менял канал. То есть анализировал бы каждую линию по очереди. Пока это есдинственное решение, которое я вижу. Единственный существенный минус - если на одном из каналов будет низкая частота, то будут тормоза.

Упирается все на самом деле не собственно в АЦП, а в analog watchdog.
Их тоже нужно по числу каналов. Я вначале попробовал включить оба АЦП - все замечательно. Задача была полность решена. Но у меня 3 канала.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.