STM32F4xx
- ddnik
- Автор темы
- Посетитель
12 года 7 мес. назад #2781
от ddnik
ddnik создал тему: STM32F4xx
Не любитель писать - но...
Не первый МК на длинном пути и снова приходится ковыряться в бесконечных регистрах, документации с дырами и изучать примитивные примеры
Недавний опыт со Stellaris говорит что можно и по другому делать...
Примеры:
С трудом нашел как включить FPU - в документации практически ни слова(по умолчанию выключен). Нашел в примере DSP - надо выставить пару битиков в некотором регистре...
Не нашел ответов (пока ищу методом проб...) по АЦП
1. можно ли независимо запускать 3 АЦП каждый по отдельному каналу DMA?
2. в кристаллах Z (144pin) написано что каналов 24 - но во всей документации описано как делать 16!??+три внутренних t, Vref,Vbat. Где остальные?
3. в DS написано максимальная частота АЦП 36 Мг но все примеры даются как 84/2= 42! Почему?
Не первый МК на длинном пути и снова приходится ковыряться в бесконечных регистрах, документации с дырами и изучать примитивные примеры
Недавний опыт со Stellaris говорит что можно и по другому делать...
Примеры:
С трудом нашел как включить FPU - в документации практически ни слова(по умолчанию выключен). Нашел в примере DSP - надо выставить пару битиков в некотором регистре...
Не нашел ответов (пока ищу методом проб...) по АЦП
1. можно ли независимо запускать 3 АЦП каждый по отдельному каналу DMA?
2. в кристаллах Z (144pin) написано что каналов 24 - но во всей документации описано как делать 16!??+три внутренних t, Vref,Vbat. Где остальные?
3. в DS написано максимальная частота АЦП 36 Мг но все примеры даются как 84/2= 42! Почему?
- ddnik
- Автор темы
- Посетитель
12 года 7 мес. назад #2786
от ddnik
ddnik ответил в теме Re: STM32F4xx
...все еще мучаюсь с АЦП...
Кое с чем разобрался (методом проб и трассировки)
По 1 вопросу - вроде можно настроить DMA на каждый АЦП отдельно
По 2 - оказывается входные каналы для разных АЦП неравнозначны! Вернее не все каналы равнозначны!
В частности каналы t, Vref,Vbat доступны только для ADC 1, а каналы ADC_Channel_4,5,6,7,8,9,14,15 ADC3 выходят на отдельные пины.
По 3 - на совести написателей.
Обнаружил брак в примерах >
Методика написания библиотечный функций в принципе дурная
для передачи битиков которые потом переносятся в регистры используется структура (почему нельзя сразу сформировать регистр? - только память расходуется!)
Отсюда потенциальная проблема - ВСЕ компоненты структуры должны быть заполнены!
Теперь берем любой пример (выдержка)
void ADC3_CH12_DMA_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
...
/* ADC3 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC3, &ADC_InitStructure);
...
результат - содержимое ADC3-CR2 = случайное число, оказывается в структуре ADC_InitStructure
есть еще один член uint32_t ADC_ExternalTrigConv, а поскольку сама структура в динамической памяти - в этой переменной "мусор"
Библиотека делает так
/*
ADCx CR2 Configuration
*/
/* Get the ADCx CR2 value */
tmpreg1 = ADCx->CR2;
/* Clear CONT, ALIGN, EXTEN and EXTSEL bits */
tmpreg1 &= CR2_CLEAR_MASK;
/* Configure ADCx: external trigger event and edge, data alignment and
continuous conversion mode */
/* Set ALIGN bit according to ADC_DataAlign value */
/* Set EXTEN bits according to ADC_ExternalTrigConvEdge value */
/* Set EXTSEL bits according to ADC_ExternalTrigConv value */
/* Set CONT bit according to ADC_ContinuousConvMode value */
tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_DataAlign | \
ADC_InitStruct->ADC_ExternalTrigConv |
ADC_InitStruct->ADC_ExternalTrigConvEdge | \
((uint32_t)ADC_InitStruct->ADC_ContinuousConvMode << 1));
/* Write to ADCx CR2 */
ADCx->CR2 = tmpreg1;
/*
ADCx SQR1 Configuration
*/
Как видно принятый мусор по "или" сваливается в CR2...
и удивляйтесь потом почему вдруг стало ADC_DataAlign_Right ???
Кое с чем разобрался (методом проб и трассировки)
По 1 вопросу - вроде можно настроить DMA на каждый АЦП отдельно
По 2 - оказывается входные каналы для разных АЦП неравнозначны! Вернее не все каналы равнозначны!
В частности каналы t, Vref,Vbat доступны только для ADC 1, а каналы ADC_Channel_4,5,6,7,8,9,14,15 ADC3 выходят на отдельные пины.
По 3 - на совести написателей.
Обнаружил брак в примерах >
Методика написания библиотечный функций в принципе дурная
для передачи битиков которые потом переносятся в регистры используется структура (почему нельзя сразу сформировать регистр? - только память расходуется!)
Отсюда потенциальная проблема - ВСЕ компоненты структуры должны быть заполнены!
Теперь берем любой пример (выдержка)
void ADC3_CH12_DMA_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
...
/* ADC3 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC3, &ADC_InitStructure);
...
результат - содержимое ADC3-CR2 = случайное число, оказывается в структуре ADC_InitStructure
есть еще один член uint32_t ADC_ExternalTrigConv, а поскольку сама структура в динамической памяти - в этой переменной "мусор"
Библиотека делает так
/*
ADCx CR2 Configuration
*/
/* Get the ADCx CR2 value */
tmpreg1 = ADCx->CR2;
/* Clear CONT, ALIGN, EXTEN and EXTSEL bits */
tmpreg1 &= CR2_CLEAR_MASK;
/* Configure ADCx: external trigger event and edge, data alignment and
continuous conversion mode */
/* Set ALIGN bit according to ADC_DataAlign value */
/* Set EXTEN bits according to ADC_ExternalTrigConvEdge value */
/* Set EXTSEL bits according to ADC_ExternalTrigConv value */
/* Set CONT bit according to ADC_ContinuousConvMode value */
tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_DataAlign | \
ADC_InitStruct->ADC_ExternalTrigConv |
ADC_InitStruct->ADC_ExternalTrigConvEdge | \
((uint32_t)ADC_InitStruct->ADC_ContinuousConvMode << 1));
/* Write to ADCx CR2 */
ADCx->CR2 = tmpreg1;
/*
ADCx SQR1 Configuration
*/
Как видно принятый мусор по "или" сваливается в CR2...
и удивляйтесь потом почему вдруг стало ADC_DataAlign_Right ???
- ddnik
- Автор темы
- Посетитель
12 года 7 мес. назад #2787
от ddnik
ddnik ответил в теме Re: STM32F4xx
... пока не разобрался- при попытке запустить в цикле измерения четырех каналов дают результат в памяти четыре измерения первого :-\
Может кто поможет (голова уже съезжает)
Текст
void ADC_CH_DMA_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable ADC3, DMA2 and GPIO clocks ****************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* DMA2 Stream0 channel0 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 4;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream0, ENABLE);
/* Configure ADC3 Channel12 pin as analog input ******************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* ADC Common Init **********************************************************/
ADC->CCR = ADC_Mode_Independent |
ADC_Prescaler_Div2 |
ADC_DMAAccessMode_1 |
ADC_TwoSamplingDelay_5Cycles |
ADC_CCR_TSVREFE | ADC_CCR_VBATE;
/* ADC3 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 4;
ADC_Init(ADC1, &ADC_InitStructure);
// Выставляю CR2 сам из-за ошибки примера
ADC1->CR2 = ADC_CR2_EOCS|ADC_CR2_CONT|ADC_CR2_DMA|ADC_CR2_DDS;
/* ADC regular configuration *************************************/
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 1, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 2, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_18, 3, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 4, ADC_SampleTime_480Cycles);
/* Enable DMA request after last transfer (Single-ADC mode) */
//ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//ENABLE);
/* Enable ADC3 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADC1, ENABLE);
}
Результат после запуска - в массиве volatile WORD ADC3ConvertedValue[32];
в первых четырех ячейках значения ADC_Channel_12...!!!
Может кто поможет (голова уже съезжает)
Текст
void ADC_CH_DMA_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable ADC3, DMA2 and GPIO clocks ****************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* DMA2 Stream0 channel0 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 4;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream0, ENABLE);
/* Configure ADC3 Channel12 pin as analog input ******************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* ADC Common Init **********************************************************/
ADC->CCR = ADC_Mode_Independent |
ADC_Prescaler_Div2 |
ADC_DMAAccessMode_1 |
ADC_TwoSamplingDelay_5Cycles |
ADC_CCR_TSVREFE | ADC_CCR_VBATE;
/* ADC3 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 4;
ADC_Init(ADC1, &ADC_InitStructure);
// Выставляю CR2 сам из-за ошибки примера
ADC1->CR2 = ADC_CR2_EOCS|ADC_CR2_CONT|ADC_CR2_DMA|ADC_CR2_DDS;
/* ADC regular configuration *************************************/
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 1, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 2, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_18, 3, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 4, ADC_SampleTime_480Cycles);
/* Enable DMA request after last transfer (Single-ADC mode) */
//ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//ENABLE);
/* Enable ADC3 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADC1, ENABLE);
}
Результат после запуска - в массиве volatile WORD ADC3ConvertedValue[32];
в первых четырех ячейках значения ADC_Channel_12...!!!
- ddnik
- Автор темы
- Посетитель
12 года 7 мес. назад #2788
от ddnik
ddnik ответил в теме Re: STM32F4xx
Ура - заработало!
Оказывается мало указать что четыре регулярных канала, надо указать что они должны переключаться!
...
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
...
Пошел осваивать изделие дальше.... На очереди работа АЦП по прерываниям (примера нет), надо реализовать прерывание после обработки каждой группы регулярных каналов.
Оказывается мало указать что четыре регулярных канала, надо указать что они должны переключаться!
...
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
...
Пошел осваивать изделие дальше.... На очереди работа АЦП по прерываниям (примера нет), надо реализовать прерывание после обработки каждой группы регулярных каналов.
- Денис Ягов
- Посетитель
12 года 6 мес. назад #2791
от Денис Ягов
Денис Ягов ответил в теме Re: STM32F4xx
Добрый день.
Обычно я поглядываю в форум, но в этот раз не мог ответить.
Вижу вы во всём разобрались.
По поводу примеров и функций.
Да. Примеры заточены под "понятность".
Тот же самый DMA - расписывается отдельной строкой каждый бит регистра.
За то вы пишете: "Инкремент адреса периферии = Энэйбл".
Это затратно с точки зрения написания (физического), расходов тактов и памяти.
Зато читаемый текст.
Именно под читаемость - заточены библиотеки.
На самом деле, дальше надо посмотреть значения регистров в пошаговой отладке (после функций типа XXXXXX_Init) и закомментарить текст программы и напрямую присвоить значение регистра (которое видели в отладчике).
По прерыванию АЦП.
Вам в проект надо включить файл типа startup_stm32f4xx.s (в нём расписаны все прерывания). Подключение этого файла в проект потребует подключения функции System_Init(), она в файле system_stm32f4xx.c. Имейте ввиду, эта функция выставляет тактирование на 168МГц - внешним кварцем с частотой 25МГц... Покопайтесь в ней (если у вас другое тактирование и/или программа - во внешней памяти).
В указанном файле startup_stm32f4xx.s - имеются названия функций, которые будут размещены в векторах прерываний. В том числе и АЦП: ADC_IRQHandler - название функции, которая будет воспринята как "прерывание от АЦП", при поступлении запроса на прерывание.
Функция, которая разрешает прерывание от АЦП:
void ADC_ITConfig ( ADC_TypeDef * ADCx,
uint16_t ADC_IT,
FunctionalState NewState
)
(разберётесь самостоятельно - тут всё просто)
Кроме того надо настроить контроллер прерываний NVIC.
Возьмёте пример настройки, замените применённую в нём периферию на АЦП (чтоб он именно эти прерывания воспринимал и ранжировал по приоритету).
Контроллер прерываний правильно настроить до запуска АЦП (генерящего прерывания).
Обычно я поглядываю в форум, но в этот раз не мог ответить.
Вижу вы во всём разобрались.
По поводу примеров и функций.
Да. Примеры заточены под "понятность".
Тот же самый DMA - расписывается отдельной строкой каждый бит регистра.
За то вы пишете: "Инкремент адреса периферии = Энэйбл".
Это затратно с точки зрения написания (физического), расходов тактов и памяти.
Зато читаемый текст.
Именно под читаемость - заточены библиотеки.
На самом деле, дальше надо посмотреть значения регистров в пошаговой отладке (после функций типа XXXXXX_Init) и закомментарить текст программы и напрямую присвоить значение регистра (которое видели в отладчике).
По прерыванию АЦП.
Вам в проект надо включить файл типа startup_stm32f4xx.s (в нём расписаны все прерывания). Подключение этого файла в проект потребует подключения функции System_Init(), она в файле system_stm32f4xx.c. Имейте ввиду, эта функция выставляет тактирование на 168МГц - внешним кварцем с частотой 25МГц... Покопайтесь в ней (если у вас другое тактирование и/или программа - во внешней памяти).
В указанном файле startup_stm32f4xx.s - имеются названия функций, которые будут размещены в векторах прерываний. В том числе и АЦП: ADC_IRQHandler - название функции, которая будет воспринята как "прерывание от АЦП", при поступлении запроса на прерывание.
Функция, которая разрешает прерывание от АЦП:
void ADC_ITConfig ( ADC_TypeDef * ADCx,
uint16_t ADC_IT,
FunctionalState NewState
)
(разберётесь самостоятельно - тут всё просто)
Кроме того надо настроить контроллер прерываний NVIC.
Возьмёте пример настройки, замените применённую в нём периферию на АЦП (чтоб он именно эти прерывания воспринимал и ранжировал по приоритету).
Контроллер прерываний правильно настроить до запуска АЦП (генерящего прерывания).
Время создания страницы: 0.038 секунд