Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F4 ADC DMA ?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Страницы: 1, 2
Allregia
Помогите пожалуйста.

Хочу запустить АЦД непрерывно на оцифровку последовательно 12 каналов, чтобы складывало с массив.
Вот код.
Не могу понять - после инициализации DMA, в его регисторах все нули.
Пробовал заускать программу - в массиве тоже все нули.
Код
//volatile u16 ADCConvertedValue[12];  <- the results are here

void adc_init(void){
ADC_InitTypeDef ADC_InitStruct;
ADC_CommonInitTypeDef ADC_CommonInitStruct;
DMA_InitTypeDef DMA_InitStructure;

         // ports are already configured    
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);          // enable clocking of ADC1
         RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2,ENABLE);          // enable clocking of DMA2    
    //==Configure DMA2 - Channel0 Stream 4==
         DMA_InitStructure.DMA_Channel                  = DMA_Channel_0;  
             DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;
         DMA_InitStructure.DMA_Memory0BaseAddr     = (uint32_t) &ADCConvertedValue;
         DMA_InitStructure.DMA_DIR             = DMA_DIR_PeripheralToMemory;
         DMA_InitStructure.DMA_BufferSize         = 12;
         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_Stream4, &DMA_InitStructure);
         DMA_Cmd( DMA2_Stream4, ENABLE);
  
// ADC:
         ADC_DeInit();     // turn ADC off

         ADC_CommonInitStruct.ADC_Mode                =ADC_Mode_Independent;
         ADC_CommonInitStruct.ADC_Prescaler            =ADC_Prescaler_Div4;
         ADC_CommonInitStruct.ADC_DMAAccessMode        =ADC_DMAAccessMode_Disabled;
         ADC_CommonInitStruct.ADC_TwoSamplingDelay            =ADC_TwoSamplingDelay_5Cycles;
         ADC_CommonInit(&ADC_CommonInitStruct);

         ADC_StructInit(&ADC_InitStruct);
         ADC_InitStruct.ADC_Resolution                =ADC_Resolution_12b;
         ADC_InitStruct.ADC_ScanConvMode            =ENABLE;
         ADC_InitStruct.ADC_ContinuousConvMode        =ENABLE;
         ADC_InitStruct.ADC_DataAlign                =ADC_DataAlign_Right;//Left;
         ADC_InitStruct.ADC_NbrOfConversion            =12;
         ADC_Init(ADC1,&ADC_InitStruct);

//----channels order
         ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1,ADC_SampleTime_480Cycles);// PC0
         ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2,ADC_SampleTime_480Cycles);// PC1
         ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3,ADC_SampleTime_480Cycles);// PC2
         ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4,ADC_SampleTime_480Cycles);// PC3
         ADC_RegularChannelConfig(ADC1, ADC_Channel_0,   5,ADC_SampleTime_480Cycles);// PA0
         ADC_RegularChannelConfig(ADC1, ADC_Channel_1,   6,ADC_SampleTime_480Cycles);// PA1
         ADC_RegularChannelConfig(ADC1, ADC_Channel_2,   7,ADC_SampleTime_480Cycles);// PA2
         ADC_RegularChannelConfig(ADC1, ADC_Channel_3,   8,ADC_SampleTime_480Cycles);// PA3
         ADC_RegularChannelConfig(ADC1, ADC_Channel_6,   9,ADC_SampleTime_480Cycles);// PA6
         ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 10,ADC_SampleTime_480Cycles);// PA7
         ADC_RegularChannelConfig(ADC1, ADC_Channel_14,11,ADC_SampleTime_480Cycles);// PC4
         ADC_RegularChannelConfig(ADC1, ADC_Channel_15,12,ADC_SampleTime_480Cycles);// PC5
// enable ADC and DMA:
         ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

         ADC_DMACmd(ADC1, ENABLE);        //Enable ADC1 DMA
         ADC_Cmd(ADC1, ENABLE);        //Enable ADC1

         ADC_SoftwareStartConv(ADC1);            // start ADC conversions
}
//-----------------------------

Проц stm32f407, J-Link, Keil 4.23
Allregia
Ошибка была чисто механическая:

RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2,ENABLE); // enable clocking of DMA2

вместо

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); // enable clocking of DMA2
ViKo
Цитата(Allregia @ Jul 23 2012, 10:27) *
Ошибка была чисто механическая:

А не надо библиотеками пользоваться. Уж сколько раз говорено. Сам прошел через это.
kan35
Цитата(ViKo @ Jul 23 2012, 11:44) *
А не надо библиотеками пользоваться. Уж сколько раз говорено. Сам прошел через это.

Вы прошли через то, что путали слова clock и reset?
и когда перестали пользоваться библиотеками, то вам помогло? laughing.gif
ViKo
Цитата(kan35 @ Jul 23 2012, 11:02) *
Вы прошли через то, что путали слова clock и reset?
и когда перестали пользоваться библиотеками, то вам помогло? laughing.gif

Нет, до этого не доходило. Но как же трудно было искать в html-документации эти функции, состав структур. Куда логичнее посмотреть содержимое регистров в руководстве на микроконтроллер, и использовать только описание этих битов из stm32f10x.h (в моем случае). И места занимает намного меньше во флэшь-памяти. А, главное, чувствуешь себя хозяином микроконтроллера, а не приемышем каким-то. sm.gif
Allregia
Цитата(ViKo @ Jul 23 2012, 09:44) *
А не надо библиотеками пользоваться.


С чего вдруг?!

Цитата
Но как же трудно было искать в html-документации эти функции,

А зачем их там искать?
Честно говоря, я даже не подозревал о существовании "html-документации", поэтому смотрю просто в .с и .h файлах самих библиотк, там зачастую более чем остаточно информации - смотрю в .с функцию, перед ней расписаны ее аргументы, все варианты.
В .h смотрю структуру и ее варанты ее параметров.
kan35
Allregia,
абсолютно правильный подход. Еще добавлю, что все библиотеки построены по одному сценарию с добавлением специфических функций соответствующих данной периферии. Весь функционал функций закодирован в имени этих функций (простите).
ViKo
Цитата(kan35 @ Jul 23 2012, 13:42) *
Allregia,
абсолютно правильный подход

Так-таки "абсолютно"?
Я инициализирую, например, порты следующим образом (с помощью своих макроопределений):
Код
;;;192    void GPIO_init(void)
000076  4849              LDR      r0,|L1.412|
;;;193    {
;;;194    /* Разрешить тактирование портов A, B, C */
;;;195      RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN;
000078  301c              ADDS     r0,r0,#0x1c
00007a  6801              LDR      r1,[r0,#0]
00007c  f0410107          ORR      r1,r1,#7
000080  6001              STR      r1,[r0,#0]
;;;196    
;;;197    /* Инициализировать GPIOA */
;;;198      GPIO_INIT(A,
000082  494b              LDR      r1,|L1.432|
000084  4849              LDR      r0,|L1.428|
000086  6008              STR      r0,[r1,#0]
000088  2000              MOVS     r0,#0
00008a  8088              STRH     r0,[r1,#4]
00008c  4a49              LDR      r2,|L1.436|
00008e  608a              STR      r2,[r1,#8]
000090  2214              MOVS     r2,#0x14
000092  60ca              STR      r2,[r1,#0xc]
000094  f44f72b8          MOV      r2,#0x170
000098  620a              STR      r2,[r1,#0x20]
00009a  4a47              LDR      r2,|L1.440|
00009c  624a              STR      r2,[r1,#0x24]
;;;199        MD_GPO, OT_PP, SP_400K, PL_NP, AF_SYSTEM,    // PA0
;;;200        MD_AF,  OT_PP, SP_400K, PL_PU, AF_USART2,    // PA1
;;;201        MD_AF,  OT_PP, SP_400K, PL_PU, AF_TIM2,        // PA2
;;;202    //    MD_GPO, OT_PP, SP_10M,  PL_PD, AF_SYSTEM,    // PA3 - Test
;;;203        MD_AN,  OT_PP, SP_400K, PL_NP, AF_SYSTEM,    // PA3 - ADC3 LQFP48
;;;204        MD_AN,  OT_PP, SP_400K, PL_NP, AF_SYSTEM,    // PA4 - ADC4
;;;205        MD_AN,  OT_PP, SP_400K, PL_NP, AF_SYSTEM,    // PA5 - ADC5
;;;206        MD_AN,  OT_PP, SP_400K, PL_NP, AF_SYSTEM,    // PA6 - ADC6 = VAC1
;;;207        MD_AN,  OT_PP, SP_400K, PL_NP, AF_SYSTEM,    // PA7 - ADC7 = VAC2
;;;208        MD_AF,  OT_PP, SP_10M,  PL_NP, AF_SYSTEM,    // PA8 - MSO (USART1)
;;;209        MD_AF,  OT_PP, SP_10M,  PL_NP, AF_USART1,    // PA9 - USART1_TX
;;;210        MD_AF,  OT_PP, SP_10M,  PL_NP, AF_USART1,    // PA10 - USART1_RX
;;;211        MD_AF,  OT_PP, SP_10M,  PL_NP, AF_USART1,    // PA11
;;;212        MD_AF,  OT_PP, SP_10M,  PL_NP, AF_USART1,    // PA12
;;;213        MD_AF,  OT_PP, SP_10M,  PL_NP, AF_SYSTEM,    // PA13 - JTMS-SWDAT
;;;214        MD_AF,  OT_PP, SP_10M,  PL_NP, AF_SYSTEM,    // PA14 - JTCK-SWCLK
;;;215        MD_AF,  OT_PP, SP_10M,  PL_NP, AF_SYSTEM);    // PA15 - JTDI
;;;216    
;;;217    /* Инициализировать GPIOB */

и т.д.
Взгляните, во что выливается код инициализации при использовании библиотечных функций. Потом посмеемся и поплачем...
kan35
Не преувеличивайте. Инициализация периферии занимает исчезающе малую долю реального кода.
Велика ли будет экономия? Позволит ли она вам взять более дешевый камень? врядли... код будет быстрее? - ну может быть при очень определенных условиях...
так за что же борьба? за идею наверное bb-offtopic.gif
ViKo
Цитата(kan35 @ Jul 23 2012, 14:47) *
за идею наверное

За нее. За "абсолютно правильный подход".

Еще пример. Сравните с кодом из сообщения топикстартера. Не убеждает?
Код
void ADC_init(void)
{
/* Разрешить тактирование ADC1 */
  RCC->CR |= RCC_CR_HSION;        // Такты на преобразователь
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;    // Такты на интерфейс

// ADON == 0 //
/* 12-bit , Power Down during Idle phase, Scan Mode */
  ADC1->CR1 = ADC_CR1_PDI | ADC_CR1_SCAN;
/* Sample Time 16 cycles (1 us) for all channels */
  ADC1->SMPR1 = ADC1->SMPR2 = ADC1->SMPR3 = 0x2<<27 | 0x2<<24 |
  0x2<<21 | 0x2<<18 | 0x2<<15 | 0x2<<12 | 0x2<<9 | 0x2<<6 | 0x2<<3 | 0x2<<0;
/* Right alignment, DMA mode disabled, No delay, ADC On */
  ADC1->CR2 = ADC_CR2_ADON;
/* Wait while !ADONS */
  while (!(ADC1->SR & ADC_SR_ADONS));
// ADONS == 1 //
/* External Trigger on the rising edge for injected channels,  TIM7_TRGO event */
  // ADC1->CR2 = ADC_CR2_JEXTEN_0 | ADC_CR2_JEXTSEL_3 | ADC_CR2_JEXTSEL_1;
  ADC1->CR2 |= ADC_CR2_JEXTEN_0 | ADC_CR2_JEXTSEL_0;        // TIM9_TRGO
/* Injected channels data offset = 0 */
/* LQFP64 - 4 injected conversions, 15, 14, 7, 6 channels */
  // ADC1->JSQR = 0x3<<20 | 15<<15 | 14<<10 | 7<<5 | 6<<0;
/* LQFP48 - 4 injected conversions, 8, 3, 7, 6 channels */  
  ADC1->JSQR = 0x3<<20 | 3<<15 | 8<<10 | 7<<5 | 6<<0;  
/* Читать регистры ADC_JDRx, когда установится бит JEOC */
}
Allregia
Цитата(ViKo @ Jul 23 2012, 13:15) *
Так-таки "абсолютно"?
Я инициализирую, например, порты следующим образом (с помощью своих макроопределений):


Может еще предложите (не дай бог, конечно) на ассемблере писать? sm.gif

Цитата
Взгляните, во что выливается код инициализации при использовании библиотечных функций. Потом посмеемся и поплачем...

А кого это .. волнует? Сколько занимает обьем инициализации, по отношению к остальной програме? 0.01% ? sm.gif
Я лично не хочу вообще думать от всяких иициализациях процессора и тому пдобной ерунде, важнее сама задача.
ViKo
Цитата(Allregia @ Jul 23 2012, 14:51) *
Может еще предложите (не дай бог, конечно) на ассемблере писать? sm.gif

На это отвечу словами kan35: Не преувеличивайте! sm.gif
Цитата
Сколько занимает обьем инициализации, по отношению к остальной програме? 0.01% ? sm.gif
Я лично не хочу вообще думать от всяких иициализациях процессора и тому пдобной ерунде, важнее сама задача.

А на это отвечу - Не преуменьшайте. Подумайте хотя бы раз. Посмотрите, сколько флэш-памяти съедает инициализация, сообщите конкретную цифру. Думаю, что и под 10% можно отхватить, для микроконтроллеров с малым объемом. Если устраивает - пользуйтесь. Меня - не устраивает.
Allregia
Цитата(ViKo @ Jul 23 2012, 13:49) *
За нее. За "абсолютно правильный подход".

Еще пример. Сравните с кодом из сообщения топикстартера. Не убеждает?


Сравнил. По сравнеиню с моим - Жуть и Кошмар sm.gif
ViKo
Цитата(Allregia @ Jul 23 2012, 15:34) *
Сравнил. По сравнеиню с моим - Жуть и Кошмар sm.gif

"Цифру, сестра! Цифру!" (с)
Allregia
Цитата(ViKo @ Jul 23 2012, 14:10) *
А на это отвечу - Не преуменьшайте. Подумайте хотя бы раз. Посмотрите, сколько флэш-памяти съедает инициализация, сообщите конкретную цифру.


Конкретно указанная выше функция занимет 70 байт.
Я наверное просто лопнул бы от счастья сьекономить на ней 10-20 байт....
И даже если бы таких инициализаций было бы полсотня (что в 5 раз болше чем в реале) - подумать только целый килобайт бы сьекономил!
Ну был бы это PIC12 или 16 я бы еще подумал....


(справедливости ради - 70 это сама функция, вызываемые ею библиотечные - еще 200, тоже офигенная экономия).

Цитата
Думаю, что и под 10% можно отхватить, для микроконтроллеров с малым объемом.


Если Вы не заметили, у используемого мною МК меньше чем с 512кБ в этой серии и не бывает.
Конкретная задача у меня сейчас заняла около 70кб.

Цитата(ViKo @ Jul 23 2012, 14:37) *
"Цифру, сестра! Цифру!" (с)


Какую "цифру"? Там Ваш текст а не цифры. Вот и текст этот - "Жуть и Кошмар" sm.gif



P.S. Но примечательно другое - я написал сообщение вчера днем. 1111493779.gif

И за весь вечер и все утро не нашлось ни одного человека. который бы чем-то помог.
Зато когда я сам написал что разобрался - тут сразу советчиков стало намного больше laughing.gif

Короче, давайте на этом закончим.
kan35
ViKo,
Оптимизация ради оптимизации приносит только потерю вашего времени к сожалению. В итоге получаете код плохочитаемый, плохопереносимый - поменять канал таймера например - целая история.
А вообще люди пишут свои USB библиотеки, TCP стеки, Оси, да что там говорить - компиляторы пишут biggrin.gif . Так что на этом фоне работать с регистрами это не такой уж страшный велосипед (или фобия).
ViKo
Цитата(Allregia @ Jul 23 2012, 15:46) *
Конкретно указанная выше функция занимет 70 байт.
Я наверное просто лопнул бы от счастья сьекономить на ней 10-20 байт....

Когда я начинал программировать STM32F103, инициализация с использованием библиотеки заняла у меня что-то около 2,7 KB. Меня это удивило.

Ваша функция adc_init() занимет 70 байтов? Не желаете ли сделать еще одно усилие, и посчитать в листинге? Было бы интересно узнать, сколько же заняла.
Моя ADC_init() заняла 80 байтов.

Цитата
P.S. Но примечательно другое - я написал сообщение вчера днем.
И за весь вечер и все утро не нашлось ни одного человека. который бы чем-то помог.

На это есть очевидная причина. sm.gif

Цитата(kan35 @ Jul 23 2012, 15:48) *
Так что на этом фоне работать с регистрами это не такой уж страшный велосипед (или фобия).

Так это мне в плюс или в минус? sm.gif
kan35
Это плюс несомненно.
А вообще, вы задавались вопросом "почему появились библиотеки периферии" - очень просто: периферия стала жутко сложная, регистры 32 битные - битов дополна. И программировать их напрямую как минимум долго, неудобно и надо постоянно рыться в референсмануале на 1000 страниц. Некоторым головастым и рукастым мужикам это вполне подсилу и они непринужденно лопатят горы информации. А таким как мне на это уйдет куча времени и сил. И за несколько лет не встретилось мне еще задачи где потребовалась бы прямая работа с регистрами.

Это конечно все лирика, но все же доверять только собственным исходным кодам практика довольно пагубная для инженера, согласитесь.
ViKo
Цитата(kan35 @ Jul 23 2012, 16:30) *
Это конечно все лирика, но все же доверять только собственным исходным кодам практика довольно пагубная для инженера, согласитесь.

Лично я не сталкивался (не помню), но на форуме проскакивали сообщения, где говорилось про ошибки в библиотеке. А чтобы найти такие ошибки, придется и по функциям пройтись, и по регистрам. Вот это, действительно, кошмар.
AlexandrY
Цитата(kan35 @ Jul 23 2012, 16:30) *
Это плюс несомненно.
А вообще, вы задавались вопросом "почему появились библиотеки периферии" - очень просто: периферия стала жутко сложная, регистры 32 битные - битов дополна. И программировать их напрямую как минимум долго, неудобно и надо постоянно рыться в референсмануале на 1000 страниц.

Это конечно все лирика, но все же доверять только собственным исходным кодам практика довольно пагубная для инженера, согласитесь.


О сложностях, кстати.
Да, периферия стала сложная поэтому не надо ее еще усложнять дополнительными абстракциями.
Для меня, например, не постижимо по названию функции TIM2_Init понять зачем она нужна и что делает.
Запомнить ее назначение можно только постоянно с ней имея дело (вынужденно, поскольку дольше приходится писать инициализацию) и детально просмотрев ее код, поскольку здесь нет ничего интуитивно понятного.
Гораздо проще найти в мануале описание таймера где все регистры описаны на паре страниц, и записать этот десяток регистров используя битовые маски.

Заимствовать исходники нужно когда они выполняют действительно объемные задачи.
А здесь пару строк записи в регистры заменяют огромными библиотеками.
VslavX
Цитата(AlexandrY @ Jul 23 2012, 23:04) *
А здесь пару строк записи в регистры заменяют огромными библиотеками.

Меня эти ST-шные "библиотеки" тоже раздражают. Сделано не слишком умно, против принципа Оккама идут - умножают сущности сверх необходимого. Особенно если нужно подсмотреть пример кода, который иллюстрирует какую-нибудь особенность работы аппаратуры - пока эту гору мусора перелопатишь и уяснишь интересующий момент...
kan35
Цитата(AlexandrY @ Jul 24 2012, 00:04) *
Для меня, например, не постижимо по названию функции TIM2_Init понять зачем она нужна и что делает.
Запомнить ее назначение можно только постоянно с ней имея дело (вынужденно, поскольку дольше приходится писать инициализацию) и детально просмотрев ее код, поскольку здесь нет ничего интуитивно понятного.
Гораздо проще найти в мануале описание таймера где все регистры описаны на паре страниц, и записать этот десяток регистров используя битовые маски.

Резонное замечание. Однако для того, чтобы впадать в отчаяние видя гору функций с непонятными именами (хотя на мой взгляд достаточно понятными) можно обратиться к примерам, которые включены в библиотеку, а так же включен пустой шаблон (template) от которого можно быстро стартовать. В этих примерах разобраны наиболее востребованные режимы работы периферии, например, для ADC приведено кажется более 10 способов обслуживания. Просто копируете оттуда нужный код и его модифицируете.
Библиотека selfdocumented и с помощью "go to definition" можно быстро прыгнуть к поснению.
Есть еще мощная штука - "Find in files" :-) - быстро все ставит на свои места
demiurg_spb
Я использую библиотеки и могу сказать, что они слегка идеологически недоделанные, т.е. приходится самому реализовывать некоторый удобный и очевидный для меня функционал. Например:
CODE
static void uart_init_rcc(uart_t* const uart)
{
switch ((uint32_t)uart->sfr)
{
case USART1_BASE: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); break;
case USART2_BASE: RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); break;
case USART3_BASE: RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); break;
#ifdef USART4
case USART4_BASE: RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART4, ENABLE); break;
#endif

#ifdef USART5
case USART5_BASE: RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART5, ENABLE); break;
#endif
default: return;
}

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // Enable AFIO clock
}

static void uart_init_nvic(uart_t* const uart)
{
switch ((uint32_t)uart->sfr)
{
case USART1_BASE: NVIC_EnableIRQ(USART1_IRQn); break;
case USART2_BASE: NVIC_EnableIRQ(USART2_IRQn); break;
case USART3_BASE: NVIC_EnableIRQ(USART3_IRQn); break;
#ifdef USART4
case USART4_BASE: NVIC_EnableIRQ(USART4_IRQn); break;
#endif

#ifdef USART5
case USART5_BASE: NVIC_EnableIRQ(USART5_IRQn); break;
#endif
default: return;
}
}

Работа с GPIO у меня полностью своя, кочующая из проекта в проект, независимо от архитектуры контроллера.
Считаю что если что-то решается гладко при помощи библиотеки стоит так и решать, ибо инициализация - это, так сказать, разовая акция и на скорость критически влиять не может.
А что то до экономии пары сотен байт байт то это смешно. И аргументы насчёт непонятных названий библиотечный функций тоже для меня не понятны...
Сергей Борщ
А почему все зациклились на инициализации? Разве библиотека не навязывает использование ее же в обработчиках прерываний и вообще в любой точке кода, в которой нужно обращение к периферии? Интересно узнать от использующих библиотеку, во что выливается библиотечная функция чтения флага прерывания? Во что выливается сброс флага или двух флагов? Без библиотеки я знаю, чего мне это стоит:
CODE
151:././../common/rf/transmitter.cpp ****         DMA1->IFCR = DMA_IFCR_CHTIF3 | DMA_IFCR_CTCIF3;
1027                      .loc 1 151 0
1028 003c 3C4B             ldr    r3, .L76+8    @ tmp165,
1029 003e 4FF4C062         mov    r2, #1536    @ tmp166,
1030 0042 5A60             str    r2, [r3, #4]    @ tmp166, MEM[(struct DMA_TypeDef *)1073872896B].IFCR
Могу ли я позволить себе тут полноценный вызов функции с подготовкой ее параметров и прочими накладными расходами? Наверное конкретно в этом случае могу, даже несмотря на то, что это обработчик прерывания. Но этот вызов будет лишь способствовать глобальному потеплению. А где-то эта лишняя задержка может уже существенно ударить по энергопотреблению или производительности конечного устройства. Полагаю, что все эти наши споры происходят лишь по одной причине - если бы обращения к библиотеке компилировались бы в такие же обращения к регистрам без лишних накладных расходов, то противников библиотеки практически не осталось бы. Я бы сам первый начал ее использовать. И чем больше людей бы ее использовали, тем быстрее в ней нашлись бы все (почтиsm.gif ) ошибки. Но пока добавляемые библиотекой накладные расходы лично для меня неприемлемы.
Кстати, будет интересно посмотреть, во что выливается DMA1->IFCR = DMA_IFCR_CHTIF3 | DMA_IFCR_CTCIF3; при использовании библиотеки.

P.S. Вообще все эти войны С/Асм, С/С++, Регистры/библиотека очень напоминают замечательный мультик: http://www.youtube.com/watch?v=JMJXvsCLu6s...player_embedded
demiurg_spb
Цитата(Сергей Борщ @ Jul 24 2012, 13:48) *
А почему все зациклились на инициализации? Разве библиотека не навязывает использование ее же в обработчиках прерываний и вообще в любой точке кода, в которой нужно обращение к периферии?
Мне она ничего не навязывает, флаги в прерываниях я без неё дёргаю, а всю инициализацию с ней. Так дело обстоит именно по озвученной вами причине. Писатели этой библиотеки не самые хорошие программисты, но как-то приходится с этим жить (свои костыли подставлять по мере реальной необходимости).
А мультик отличный! sm.gif
Allregia
Цитата(Сергей Борщ @ Jul 24 2012, 11:48) *
А почему все зациклились на инициализации? Разве библиотека не навязывает использование ее же в обработчиках прерываний и вообще в любой точке кода, в которой нужно обращение к периферии?


Не знаю как другим, а мне - не навязывает. Я пользуюсь библиотеками, но там где time critical и надо шевелить ножками или флагами, пишу обычно типа:
Код
__INLINE void TestPinOn(void)    { GPIOD->BSRRL = GPIO_Pin_15; }      // 1=on,
__INLINE void TestPinOff(void)   { GPIOD->BSRRH = GPIO_Pin_15; }    // 0=off
__INLINE void TestPinToggle(void){ GPIOD->ODR  ^= GPIO_Pin_15; }
demiurg_spb
Цитата(Allregia @ Jul 24 2012, 21:42) *
Код
__INLINE void TestPinOn(void)    { GPIOD->BSRRL = GPIO_Pin_15; }      // 1=on,
__INLINE void TestPinOff(void)   { GPIOD->BSRRH = GPIO_Pin_15; }    // 0=off
__INLINE void TestPinToggle(void){ GPIOD->ODR  ^= GPIO_Pin_15; }
Уууу.... Макросы имени Аскольда Волкова вам в помощь и гугл тоже:-)
_Артём_
Цитата(demiurg_spb @ Jul 24 2012, 20:47) *
Уууу.... Макросы имени Аскольда Волкова вам в помощь и гугл тоже:-)

А что "Уууу"?
Надо выход изменить - записал в OUTSET/OUTCLR нужного порта число.
Зачем тут макросы? Сахар это? Нет?
demiurg_spb
Тот кто привык щи лаптем хлебать того уже более прогрессивным прибором не заманишь к столу.
Без обид...

Вы внимательнее ознакомьтесь с этими макросами и возможно осознаете всю их прелесть.

Конечно их можно и нужно заменить на шаблоны при переходе на с++, ну а для си более красивого подхода акромя макросов не сыскать.
Allregia
Цитата(demiurg_spb @ Jul 24 2012, 19:47) *
Уууу.... Макросы имени Аскольда Волкова вам в помощь и гугл тоже:-)


Я и без гугла в курсе, но мне так удобнее.
_Артём_
Цитата(demiurg_spb @ Jul 24 2012, 22:05) *
Тот кто привык щи лаптем хлебать того уже более прогрессивным прибором не заманишь к столу.
Без обид...

Да какие обиды...
Вопрос в их прогрессивности.
Чем такой варинт хуже
Код
__INLINE void TestPinOn(void)    { GPIOD->BSRRL = GPIO_Pin_15; }

?
Тем более при усложнившейся структуре портов.
Не усложнятся ли макросы до полной непонятности?
Получится тоже что "писать в регистры" vs "использовать библиотеку".

Цитата(demiurg_spb @ Jul 24 2012, 22:05) *
Вы внимательнее ознакомьтесь с этими макросами и возможно осознаете всю их прелесть.

Всё возможно...


Цитата(demiurg_spb @ Jul 24 2012, 22:05) *
Конечно их можно и нужно заменить на шаблоны при переходе на с++

Теоритически можно, и наверное нужно. Но как-то руки не доходят.

Allregia
Цитата(_Артём_ @ Jul 24 2012, 21:57) *
Да какие обиды...
Вопрос в их прогрессивности.
Чем такой варинт хуже
Код
__INLINE void TestPinOn(void)    { GPIOD->BSRRL = GPIO_Pin_15; }

?


ДА ничем. ТЕм более, что я показал самый простой вариант. В общем виде порт и пин задаются дефайнами а не в явном виде. А при наличии __INLINE это считай тот-же макрос.
demiurg_spb
Цитата(_Артём_ @ Jul 24 2012, 23:57) *
Чем такой варинт хуже
Код
__INLINE void TestPinOn(void)    { GPIOD->BSRRL = GPIO_Pin_15; }
?

этот теоретически ничем, а вот с инверсией INLINE процедура содержит реальную багу (не обеспечивает атомарного доступа) и при условии что в прерываниях происходит запись в тот же порт будут танцы с бубном. Чтобы пофиксить это нужно работать через bitband или переписать как
Код
if (pin==1) pin=0; else pin=1;

Поищите по форуму, это уже обсуждалось не один раз.

Цитата
Тем более при усложнившейся структуре портов.
Не усложнятся ли макросы до полной непонятности?
Получится тоже что "писать в регистры" vs "использовать библиотеку".

Нет ничего не усложнится. Суть этих макросов в повторном использовании кода с целью сделать проект прозрачным, переносимым и легко модифицируемым.

В случае не использования макросов вам придётся писать для каждого пина снова и снова по 3-4 инлайн процедуры, потом при переразводке платы снова править в 3-4 местах и не дай Бог где-то что-то упустить. Неужели это радостная и продуктивная работа?

Цитата(Allregia @ Jul 25 2012, 09:24) *
В общем виде порт и пин задаются дефайнами а не в явном виде.
А потом вдруг требуется инвертировать один из сигналов по какой-либо причине. И? Сели в лужу?
Allregia
Цитата(demiurg_spb @ Jul 25 2012, 07:47) *
А потом вдруг требуется инвертировать один из сигналов по какой-либо причине. И? Сели в лужу?


Ну так я потрачу 5 минут своего драгоценного времени, на то чтобы поменять в одном месте местами BSRRL и BSRRH, только и всего.
Все равно 99.999% времени занимает основная задача, а не настройка портов и т.п.
Я даже на PIC16 таким не заморачивался, хотя понятное дело что сложность решаемых задач там пониже.

Помнить все флаги и биты регистров это конечно хорошо, но я предпочитаю их посмотреть в букваре когда пишу настройки и работу с периферией, а после этого сразу поскорее забыть sm.gif
ViKo
Цитата(Allregia @ Jul 25 2012, 10:18) *
Помнить все флаги и биты регистров это конечно хорошо, но я предпочитаю их посмотреть в букваре когда пишу настройки и работу с периферией, а после этого сразу поскорее забыть sm.gif

Но, видимо, на регистры и биты ADC, DMA у вас аллергия? sm.gif
Такой стиль называется "эклектика".
Allregia
Цитата(ViKo @ Jul 25 2012, 09:30) *
Но, видимо, на регистры и биты ADC, DMA у вас аллергия? sm.gif
Такой стиль называется "эклектика".


У меня не аллергия, но делая прибор на процессорах типа Кортексов, я хочу сосредатачиваться на основной задаче, а не на побочных, типа настойки периферии.
Т.е. если у меня идет прием ЭКГ (электрокардиограммы) с АЦП, обработка и выдача результатов на дисплей и в УАРТ, то 99.99% времени я предпочитаю тратить не на настройку АЦП, дисплея и УАРТа, и копание в их битах, а на прикладные вопросы, связанные с ЭКГ и ее обработкой и отображением. Что поверьте мне, гораздо более трудоемко и наукоемко.
(тем более, что кроме программы я еще и все железо делаю).
ViKo
Цитата(Allregia @ Jul 25 2012, 14:48) *
99.99% времени я предпочитаю тратить не на настройку АЦП, дисплея и УАРТа, и копание в их битах, а на прикладные вопросы, связанные с ЭКГ и ее обработкой и отображением. Что поверьте мне, гораздо более трудоемко и наукоемко.

Верю. Достойное дело. Но если использовать библиотечные функции для работы (не инициализации) с периферией, то можно понапрасну растерять производительность микроконтроллера, так, что на фильтрацию и отображение уже и не хватит.
kan35
ViKo,
никто не отрицает, что работа через библиотеки менее эффективна, чем прямая работа с регистрами - это очевидно и ни для кого не секрет. Но следует здраво оценивать баланс между потерями и преимуществами. Наверное в 99% задач пофиг - как будет управляться периферия. Возможно, у некоторых (может быть у вас, кстати), задач критичных к этому будет 100%, а у некоторых как у меня - 0% и таких как я - большинство я уверен :-) .
Для абсолютных противников библиотек они все же могут быть полезны как учебник по работе с периферией.
Из этого я делаю вывод, что библиотеки - это хорошо.
ViKo
Цитата(kan35 @ Jul 25 2012, 15:26) *
никто не отрицает, что работа через библиотеки менее эффективна, чем прямая работа с регистрами - это очевидно и ни для кого не секрет. Но следует здраво оценивать баланс между потерями и преимуществами. Наверное в 99% задач пофиг - как будет управляться периферия. Возможно, у некоторых (может быть у вас, кстати), задач критичных к этому будет 100%, а у некоторых как у меня - 0% и таких как я - большинство я уверен :-) .
Для абсолютных противников библиотек они все же могут быть полезны как учебник по работе с периферией.
Из этого я делаю вывод, что библиотеки - это хорошо.

Еще недавно вы утверждали, что это использование библиотек - это абсолютно правильный путь. Надо думать, что сейчас у вас уже нет такой 100% уверенности? sm.gif
Я не считаю себя противником того, что кто-то сделал до меня. Наоборот, всегда полезно посмотреть. Например, когда подберусь к USB, буду смотреть и в библиотеку. Но, например, когда хотел разобраться с SPI, быстро задвинул библиотеку подальше. Разбираться с ней мне показалось бессмысленной тратой времени. Невозможно понять работу железа, пользуясь готовыми функциями. Думаю, то же произойдет и с USB.
Мне казалось, что на 72 MHz все будет летать. Ан нет... laughing.gif
Allregia
Цитата(ViKo @ Jul 25 2012, 13:57) *
Верю. Достойное дело. Но если использовать библиотечные функции для работы (не инициализации) с периферией, то можно понапрасну растерять производительность микроконтроллера, так, что на фильтрацию и отображение уже и не хватит.


Можно. Но можно также голову иметь, и понимать что когда можно, а что когда нельзя (я ведь выше писал про time critical места).
И смею Вас уверить, за 25+ лет общения с разными МК, я этому чуть-чуть научился.

Цитата
Но, например, когда хотел разобраться с SPI, быстро задвинул библиотеку подальше. Разбираться с ней мне показалось бессмысленной тратой времени.


И совершенно напрасно. К примеру, в одном варианете этого устройства у меня дисплей на SPI сидит (в другом - на FSMC), у меня нет ни малейшего желания разбиратсья как там вычисляются коэффициенты делителей для SPI и UARTов, поэтому мне проще написать Baud=115200; и Init() чем самому соображать.
И для этого библиотеки вполне пригоды.
А про realtime работу - никто не мешает и напрямую с флагами/регистрами, см. выше.

Цитата
Невозможно понять работу железа, пользуясь готовыми функциями. Думаю, то же произойдет и с USB.


Чтобы понять как железо устроено - надо даташит читать, но это вовсе не отменяет пользование бибиотеками.
И вот в USB так у меня точно без не то что библиотк, а вообще драйверов, никакого желания ковыряться не возникнет.
kan35
Цитата(ViKo @ Jul 25 2012, 16:50) *
Еще недавно вы утверждали, что это использование библиотек - это абсолютно правильный путь. Надо думать, что сейчас у вас уже нет такой 100% уверенности? sm.gif
Я не считаю себя противником того, что кто-то сделал до меня. Наоборот, всегда полезно посмотреть. Например, когда подберусь к USB, буду смотреть и в библиотеку. Но, например, когда хотел разобраться с SPI, быстро задвинул библиотеку подальше. Разбираться с ней мне показалось бессмысленной тратой времени. Невозможно понять работу железа, пользуясь готовыми функциями. Думаю, то же произойдет и с USB.
Мне казалось, что на 72 MHz все будет летать. Ан нет... laughing.gif

Viko, вы любите передергиватьwink.gif
Если у вас "не летает" на 72 МГц, то стоит задуматься над тем как вы работаете с периферией. Как правило упомянутая вами работа с битами-флагами это подход который стоит применять в исключительных случаях. Вся основная работа должна происходить по DMA. У меня напрмер прекрасно уживаются mp3 плеер с tcp/ip, usb-msd и пользовательским интерфейсом и при этом проц в самом худшем случае 50% времени бездельничает. Я пользуюсь периферийной библиотекой (в том числе usb от st) :-)
Но если тот же SPI или ADC обслуживать поллингом битов, то никакого быстродействия не хватит (даже напрямую обращаясь к регистрам), не говоря уже о том, что нужно данные готовить или обрабатывать.
ViKo
Цитата(kan35 @ Jul 26 2012, 08:52) *
Viko, вы любите передергиватьwink.gif

Да ну. Так, по мелочам придирки. Шутки.
Цитата
Вся основная работа должна происходить по DMA.

Вот вам мой пример. Пересылаю из внешней ОЗУ в контроллер ЖКИ. По ПДП оказалось медленнее, чем программно.
Код
void DpyBuf2LCD_copy(uint32_t Offset, uint32_t Size)
{
/*
  LED_on();
  DMA2->IFCR |= DMA_IFCR_CTCIF1;        // сбросить флаг прерывания
  DMA2_Channel1->CCR &= ~0x00000001;        // запретить пересылку
  DMA2_Channel1->CPAR = DPYBUF + Offset;    // начальный адрес буфера экрана
  DMA2_Channel1->CMAR = LCDRAM + Offset;    // начальный адрес памяти ЖКИ
  DMA2_Channel1->CNDTR = Size/2;        // 16-битовые пересылки  
  DMA2_Channel1->CCR |= 0x00000001;        // разрешить пересылку
//  while (!(DMA2->ISR & DMA_ISR_TCIF1));    // ждать флаг прерывания
  LED_off();
*/
/*
// Программная пересылка буфера в контроллер ЖКИ
  uint16_t *pSour = (uint16_t *)(DPYBUF + Offset);
  uint16_t *pDist = (uint16_t *)(LCDRAM + Offset);
  LED_on();
  for (uint32_t i=Size/2; i--; ) {
    *pDist++ = *pSour++;
  }
  LED_off();
*/

// Программная пересылка буфера в контроллер ЖКИ 32-битовыми словами
  uint32_t *pSour = (uint32_t *)(DPYBUF + Offset);
  uint32_t *pDist = (uint32_t *)(LCDRAM + Offset);
//  LED_on();
  for (uint32_t i=Size/4; i--; ) {
    *pDist++ = *pSour++;
  }
//  LED_off();  
}
kan35
То, что по DMA работа (пусть даже внешняя память--внешняя память) оказалась медленнее - сюрприз. Ваши версии - почему этот нелогичный эффект получился, может быть DMA перегружен другой задачей?

Мы немного отклонились от темы, но у раз речь зашла, из своей практики скажу. В свое время делал драйвер для LCD контроллера на SPI, так благодаря DMA получилось даже сделать аналог графического ускорителя - рисование гор/верт линий было аппаратным, что очень ускорило работу того же ucGUI 320*240*16бит на SPI. Когда патался оптимизировать программный способ передачи, то работало в 2-4 раза медленнее, не говоря о том, что CPU только дисплеем и занимался.
ViKo
Цитата(kan35 @ Jul 26 2012, 11:36) *
То, что по DMA работа (пусть даже внешняя память--внешняя память) оказалась медленнее - сюрприз. Ваши версии - почему этот нелогичный эффект получился, может быть DMA перегружен другой задачей?

Все связано с внутренними шинами микроконтроллера. В данном примере был STM32F103. Окончание пересылки проверялось программно. Таким образом, микроконтроллер пытался параллельно выполнять код и пересылать из памяти в память. Еще отладчик Keil uLink-ME висел, он тоже что-то забирал.
Ну, и программные пересылки я сделал 32-битовыми словами. Не помню, можно ли такое сделать по ПДП.

P.S. В STM32F2, F4 есть Bus matrix, там таких тормозов уже не будет, наверное.
kan35
Действитеьлно, флаг ловить лучше в прерывании. DMA с 32 битными словами работает отлично.
ViKo
Цитата(kan35 @ Jul 26 2012, 11:58) *
Действитеьлно, флаг ловить лучше в прерывании.

100%? А потом что с ним делать?
kan35
В основной программе ждать семафора, в прерывании взводить семафор. А во время ожидания другие задачи получают процессорное время.
Я, кстати, еще ни одного проекта на кортексах не сделал без RTOS, если не считать бутлодеры к ним. В случае без ОСи следует искусственно отдавать вычислительные ресурсы другим задачам - машинами состояний как то.

Как вариант -можно уводить CPU в Wait for event. Полюбому DMA работает быстрее процессора.
Allregia
Вопрос немного в сторону, про М4 и настройки Кейла.
Вот окно настроек:
Нажмите для просмотра прикрепленного файла

У меня как-то раньше на LPC17xx небыло нужды туда лазить, оставлял все по дефолту.
Но тут во первых наконец хочеться разобраться что к чему, во вторых есть вопрос по F4.
Слепа ПЗУ, справа ОЗУ. И там есть ROM*/IROM* и RAM*/IRAM*.
Насколько я понял. ROM* и RAM* это если цепляются внешние на FSCM, а пурвая буква "i" означает "internal", т.е то что внутри проца.
Разбивать IROM на 2 части может понадобится для собственного бутлоадера а таже для использования части флеша как ЕЕПРОМ.
Радиобаттоны возле ROM* определяют откуда стартовать.
А вот что делает чексбокс default?

Далее - с RAM. Тут тоже можно разбить на 2 области, но для к примеру LPC17хх или для F1 не обчень понятнодля чего это надо.
И для чего нужны чекбоксы "No Init" рядом с ними?
В Кейле нет возможности сказать про какую-то переменную, что ее не надо инициализировать при старте (аналог persistant в Hi-Tech)?

А главное - у F4 две области памяти, общая 128к плюс 64к только для CPU.
Keil по умолчанию ставить первую, а вторую не использует.
По идее, правильнее всего было бы размещать в первой только е переменные, которым нужно DMA, а те, к которым обращается только процессор - во второй.
Но как распределять иак переменые и как обьяснить это линкеру?

ViKo
На все ваши вопросы здесь уже были ответы. Поищите по нику aaarrr.
Allregia
Цитата(ViKo @ Jul 31 2012, 11:35) *
На все ваши вопросы здесь уже были ответы. Поищите по нику aaarrr.

Просто так не ищется, может быть Вы подскажите строку для поиска?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.