Arduino IDE + аддон от stm32

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Предлагаю тут пообсуждать аддон от STM, и всё, что так или иначе с ним связано: глюки, особенности, сравнение с другими аддонами, примеры использования, итд итп.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Для тех кто совсем не в курсе, но хочет понять о чём тут речь -
Arduino IDE "из коробки" не поддерживает микроконтроллеры  STM32
Несколько энтузиастов сделали варианты дополнения, благодаря которому такая поддержка
появилась. Самый известный вариант сейчас  -аддон от Роджера Кларка. https://github.com/rogerclarkmelbourne/Arduino_STM32
Это усовершенствованный вариант от компании Лифлабс, который та давным давно забросила.
Но  теперь и этот аддон оказался заброошен, а сайт stm32duino.com лежит уже несколько месяцев.
Дополнено: сайт поднялся, аддон развивается дальше.

Наиболее перспективный на мой взгляд аддон от самих STM (судя по всему пока неофициальный) https://github.com/stm32duino/Arduino_Core_STM32
Он развивается, пополняется,  в общем заслуживает внимания.
Список поддерживаемых плат и контроллеров https://github.com/stm32duino/Arduino_Core_STM32#boards-available
Установка https://github.com/stm32duino/wiki/wiki/Getting-Started

Замеченные мной баги:
-может глюковать при компиляции если системная временная папка у вас находится где-то на виртуальном рам-диске.
-аддон может не устанавливаться с сообщением Error downloading и.т.д.  как лечить написано тут
  https://github.com/stm32duino/BoardManagerFiles/issues/15
-может глюковать если в IDE уже установлен аддон от Роджера Кларка.

Отличия этого аддона от варианта  Роджера Кларка:
- (самое главное) больше поддерживаемых МК
- тот основан на библиотеке Libmaple, а этот на CMSIS & HAL.
- есть выбор в меню платы создавать USBCDC или нет.
- использует собственный компилятор (а не компилятор от Due как было  в том)

Варианты загрузки прошивки, которые есть в аддоне:

-STM32CubeProgrammer(SWD)
 обычная загрузка через программатор. Если у вас Stlink версии 2.0, то он не поддерживается, нужно 2.1
 Можно  переделать ваш 2.0 в 2.1 по этой статье. https://habr.com/ru/post/442290/
 Или сделать программатор из блюпилл по этой статье. https://istarik.ru/blog/stm32/107.html
 Я переделал свой, теперь в програматоре и комп-порт появился, очень удобно.
 Так же нужно дополнительно установить STM32CubeProg  https://www.st.com/en/development-tools/stm32cubeprog.html

-STM32CubeProgrammer(Serial)
  Видимо заливка через аппаратный сериал, не проверял.

-STM32CubeProgrammer(DFU)
  заливка через заводской загрузчик. В 103 серии его нет. В F401
  нужно нажать кнопку boot, а потом кнопку reset, и пойдёт загрузка.
 -BMP (Black Magic Probe)
  заливка через одноимённый программатор (не проверял)
-Hid Bootloader 2.2
 Существует только для F103 и F407 https://github.com/Serasidis/STM32_HID_Bootloader
 Проверил, довольно удобная штука. Но я планирую эксперементировать на F401, так что использовать не смогу.
 

Убедительная просьба не нажимать кнопку цитировать, иначе у меня не будет возможности дополнять этот пост

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Собссно переход на этот аддон был вынужденный, из-за этой платки

О которой недавно писал a5021 в теме "интересное на Али"  При цене 230 рублей и параметрах 84MHz 64кб ram 256кб rom неплохой конкурент народному блюпилу на F103. Но меня меня эта плата интересовала в основном наличием двух 32-битных таймеров. Как выяснилось по части регистров в ней довольно много отличий от F103, GPIO и DMA прямо существенно переделаны.

Идею первого примера взял отсюда http://www.cyberforum.ru/blogs/204791/blog5169.html
Это мигалка светодиодом через DMA, практической ценности никакой, но одним махом можно проверить
связку таймера, дма и gpio. Выяснилось что теребить биты в портах gpio может только DMA2. И единственный таймер, под такты которого это можно делать -таймер1.
Кратко принцип работы:
Таймер раз в секунду делает update, и это событие отлавливает дма2, который в свою очередь
бёрет поочередно байты из массива, и суёт их в регистр управления битами порта.
И светодиод мигает :)

uint32_t ledstate[2] ={1<<29, 1<<13};
void setup() {
pinMode (PC13,OUTPUT);
RCC->AHB1ENR |=1<<22;// dma2 clock enable 
RCC->APB2ENR |= 1;// tim1 clock enable 
TIM1->DIER=(1<<8); //тактировать DMA при событии: Update timer
TIM1->PSC=8400; //поделить тактовую на..
TIM1->ARR=10000;// и ещё раз на 10 тыщ (период 1 секунда)
TIM1->CR1=1; //запуск таймера
DMA2_Stream5->CR= (6<<25)|(10<<11)|(1<<10)|(1<<8)|(1<<6);//Ch:6,WORD,MINC,CIRC,Mem2per
DMA2_Stream5->PAR= (uint32_t)&(GPIOC->BSRR);//управлять регистром BSRR
DMA2_Stream5->M0AR=(uint32_t)ledstate; 
DMA2_Stream5->NDTR=2; DMA2_Stream5->CR|= 1;//запуск DMA
}

void loop() {}

 

b707
Offline
Зарегистрирован: 26.05.2017

насчет загрузчика - а бутлоадер Кларка (https://github.com/rogerclarkmelbourne/STM32duino-bootloader)  это какой. через DFU?  И, кстати, нельзя использовать этот бут  с новым аддоном?

В переходе от аддона Кларка на аддон СТМ меня останавливает несколько реализованных проектов на старом аддоне. И, если не ошибаюсь, куда более глубокая поддержка железа у Кларка. В частности, в аддоне от СТМ нет ДМА, а у Кларка есть...

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

b707, бутлоадер Кларка это почти тот же HID bootloader, только с жестко привязанным  к нему USBCDC. Т.е. формально его HID уже нельзя назвать :)

С поддержкой DMA всё в порядке, я же привёл пример.  Можно писать на HAL, тут уж кому как нравится. Я предпочитаю CMSIS

b707
Offline
Зарегистрирован: 26.05.2017

dimax пишет:

С поддержкой DMA всё в порядке, я же привёл пример.  Можно писать на HAL, тут уж кому как нравится. Я предпочитаю CMSIS

Спасибо,  когда отвечал, Вашего примера еще не было. Поизучаю

Я имел в виду, что у Кларка были готовые методы верзнего уровня для использования ДМА, такие как SPI_DMA_Transfer() и тп. А тут их "ручками" придется писать :)

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

b707, про SPI не знаю, я пока только светодиодом научился мигать :-)))

nik182
Offline
Зарегистрирован: 04.05.2015

В HAL есть все готовые стартеры верхнего уровня. Гораздо больше чем у Кларка, да и управление оборудованием шире. Уже нарывался на таймеры. Без CMSIS было не сделать на Кларковских. 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

да, тоже сначала изучал аддон от Кларка, после как dimax дал ссылку на этот

https://github.com/rogerclarkmelbourne/Arduino_STM32

решил его пощупать, тут функционал побогаче, ну блин времени - хрен.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

подпишусь

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

описание платки от китайцев 401 чип

https://yadi.sk/d/98m6jZl7zPgwiQ

и 411

https://yadi.sk/d/bSAlrNf0HAh4ag

 

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

xDriver пишет:

описание платки от китайцев 401 чип

Схема к сожалению не от нашей платы.

Кто нить опознал что за элемент стоит около кварца (название a748n) две ноги которого приходят на пины PC15,PC14  Кварц на 32768?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

xDriver пишет:

описание платки от китайцев 401 чип

https://yadi.sk/d/98m6jZl7zPgwiQ

и 411

https://yadi.sk/d/bSAlrNf0HAh4ag

 

 

И от меня категорическое спасибо! 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Первая сложность -не могу объявить прерывание таймера средствами CMSIS.
По идее должно быть так:
void TIM2_IRQHandler(void) {  }

но программа виснет, т.к. компилится оно с другим именем. (Компилятор С++ так работает)
Меняю на extern "C" void TIM2_IRQHandler(void) {  }      -ругается:
HardwareTimer.cpp:(.text.TIM2_IRQHandler+0x0): multiple definition of `TIM2_IRQHandler';
Оказывается  ардуиновский драйвер таймера уже занял все эти имена !!! :((
Вычищать его и системы как то слишком топорно.. нужно какое-то красивое решение. Но какое?

 

Волшебник
Offline
Зарегистрирован: 22.12.2016

Не так много вычищать, мне недавно понадобился таймер-2 для энкодера на моей Ф446рэ, просто замаркировал в ардуиновском timer.c

// --MOD 30-09-2019 - Enkoder debug
/*
#if defined(TIM2_BASE)
void TIM2_IRQHandler(void)
{
  if (timer_handles[TIMER2_INDEX] != NULL) {
    HAL_TIM_IRQHandler(timer_handles[TIMER2_INDEX]);
  }
}
#endif //TIM2_BASE
*/

И декларировать:


#ifdef __cplusplus
    extern "C" {
#endif
    
  void TIM2_IRQHandler(void);
  void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim);

#ifdef __cplusplus
    }
#endif


 
void TIM2_IRQHandler(void)
{
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);  
  static int32_t last_time = 0;
   
  HAL_TIM_IRQHandler( &Encoder_Handle );
  timer2_cnt = TIM2->CNT;
  timer2_cnt /= 4;
  int32_t new_time = TIM6->CNT;
  timer6_dif = new_time - last_time;
  last_time = new_time;
  
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);  
}

 Таймеры если прерывания не нужны сразу смис понимают, сложнее запустить дуал - трипле - квадро АЦП и ЦАП, там ардуина вцепилась зубами и ломать не хотелось пост-иниты, по лени как-нить аналогРид шмыгнуть. Короче пришлось переписать СМИС, вместо ХАЛ_   май_ХАЛ_

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Волшебник, спасибо, интересный вариант.

Вчера попробовал организовать прерывание по "правилам ардуины". Мигалка светодиодом в прерывании (для stm32f401). Что удобно на 32-битном таймере -это его огромный диапазон счёта. Без всяких прескалеров можно считать до  почти минуты ( 2^32/F_CPU ) с разрешением 12nS  Описание: таймер отсчитывает 84 мульёна тиков и сбрасывается в ноль поднимая флажок прерывания.  В прерывании инвертируется состояние пина PC13, на котором висит светодиод.


void setup() {
pinMode(PC13,OUTPUT);
RCC->APB1ENR|=1<<0; //tim2 clock enable
TIM2->DIER=1<<0;// Update interrupt enable
TIM2->ARR=84000000;//1 sec
TIM2->CR1=1;
NVIC_EnableIRQ(TIM2_IRQn);
HardwareTimer *tim2 = new HardwareTimer(TIM2);
tim2->attachInterrupt(led_blink);
}

void led_blink(HardwareTimer*){
digitalToggle(PC13);
}


void loop() {}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Очередной примерчик для stm32F401. Преобразователь напряжение -> PWM

Напряжение 0..3,3в приходит на ADC8(PB0), в конце оцифровки DMA по отмашке АЦП подхватывает полученное значение, и кидает его в регистр сравнения таймера 4. С ноги PB6 снимается PWM сигнал частотой примерно 1кГц

void setup() {
pinMode(PB0,INPUT_ANALOG);//вход АЦП
RCC->AHB1ENR |= (1<<22);//enable clock: dma2 
RCC->APB1ENR |=1<<2;// enable clock:tim4
RCC->APB2ENR |= 1<<8;// enable clock: ADC1

ADC1->CR2=(3<<0)|(1<<8)|(1<<9);//En_ADC,Continuous,en_DMA,DMA.dis.sel. 
ADC1->SQR3 = 8<<0;//chanel=ADC8 
ADC1->SMPR2=7<<0;//SMP0:111 ( sampling time 480 (+12) cycles 84MHz ~6uS)
ADC1->CR2|=(1<<30);//start

DMA2_Stream0->CR= (1<<13)|(1<<11)|(1<<8);//Ch:0,16bit,CIRC,per2mem
DMA2_Stream0->PAR= (uint32_t)&(ADC1->DR); 
DMA2_Stream0->M0AR=(uint32_t)&TIM4->CCR1 ; 
DMA2_Stream0->NDTR=1; 
DMA2_Stream0->CR|= 1;//запуск DMA

GPIOB->MODER |= 1<<13; //PB6  Alternate function mode
GPIOB->AFR[0] |= 1<<25; //af02                       
TIM4->ARR=4096;
TIM4->PSC=82;
TIM4->CCMR1= 7<<4; //PWM2 
TIM4->CCER|=1<<0;
TIM4->CR1=1;
}

void loop() {}

 

Волшебник
Offline
Зарегистрирован: 22.12.2016

На 1 кГц, и ДМА? Эдак мегагерца 3+, понятно было бы. А ШИМ на 3-х каналах, 12-битку разбить на 3-и 4-х битки и "барстом" их по дма закатать в три канала.

Я как раз сейчас мудрю такой дэдээс генератор, на 446ре хоть и есть цап, но он шумный собака, а мне -100 дБси надо. Вобщем заработало, но с прерываниями опять 25-ть какой-то. Если халовскую HAL_TIM_DMABurst_WriteStart пихаю, прерываниям кирдык,

void DMA2_Stream5_IRQHandler(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);  
  HAL_DMA_IRQHandler(&hdma_tim1);
  //  HAL_DMA_IRQHandler(htim1.hdma[TIM_DMA_ID_UPDATE]);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);  
}
 
А вот ежли "вручную" 
  TIM1->DCR = (TIM_DMABASE_CCR1 | TIM_DMABURSTLENGTH_3TRANSFERS);
 
  Serial.print(F("\n\tDMA_Start_IT..."));
  delay(100);
  if (HAL_DMA_Start_IT( htim1.hdma[TIM_DMA_ID_UPDATE], (uint32_t) buff, TIM1_DMAR_A,
                        (3 *BUF_SIZE)) != HAL_OK) { Error_Handler(); }
 
  Serial.print(F("\n\tTIM_Enable_DMA..."));
  delay(100);
  __HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_UPDATE);
тогда с прерываниями всё О-К. Вобщем они -интерапты на 2.8МГц мне всё равно не покатят - вызов около микросекунды - т.е. до метра а хана, но всё равно любопытно, какого хрена отказывается вызывать стандартный обработчик в первом случае?

 

nik182
Offline
Зарегистрирован: 04.05.2015

Я таки поинтересуюсь, зачем макрос F в принтах? Какой смысл он имеет в STM? Пространство адресов линейно и не зависит от типа памяти.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Волшебник, может там в прерывании какой флажок снять надо?  Я ещё прерывания DMA не пробовал. Кстати зачем оно в вашем  конкретном случае?

b707
Offline
Зарегистрирован: 26.05.2017

dimax пишет:

 Я ещё прерывания DMA не пробовал. Кстати зачем оно в вашем  конкретном случае?

наверно банальщину скажу - но прерывания DMA в первую очередь нужны, чтобы знать, что асинхронный DMA_Transfer закончился... вот и у Волшебника тут какой-то буфер куда-то передается...

Волшебник
Offline
Зарегистрирован: 22.12.2016

Так ента штука и должна все флаги пробить, HAL_DMA_IRQHandler(&hdma_tim1);

А вообще прерывания по дма у меня при работе с ацп, полный буфер, наполовину - какую часть буффера хапать, в реал-тайм. Ну и цап-ом тож самое, апдейтить цаповский буффер при переходе блока через "0" - глитчев избегать.

В том примере выяснилось что прерывания там ни к чему, сначала думал будет одно на блок данных, в блоке триплеты байтов для шимов - подробнее в главе 5 AN4776 Application note General-purpose timer cookbook

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

А вообще дэдээс получился, но параметры по шумам хуже чем у встроенного цапа, проводки 20 см дюпоны как антенны, всё на ушах стоит. 

AlexZR
Offline
Зарегистрирован: 08.02.2016

 а можно в Arduino IDE для stm32 как то сохранить скетч в HEX а не в BIN ?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

AlexZR,  обсуждаемый аддон сохраняет оба варианта.

Feofan
Offline
Зарегистрирован: 28.05.2017
Попытка приобщения.
Скетч:
void setup() {
  Serial.begin(38400);
  Serial1.begin(38400);
  Serial2.begin(38400);
}
void loop() {}

Настройка VSCode:

Результат компиляции: undefined reference to `Serial2'
 
Изменения Upload method, USART support, USB support на результат не влияют - соглашается только на Serial и Serial1. У STM32F103C8 uart'ов три? Как добраться до Serial2?

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Feofan пишет:

Результат компиляции: undefined reference to `Serial2'

По-умолчанию объявлен только Serial1, надо объявить остальные:

HardwareSerial Serial2(PA3,PA2);
HardwareSerial Serial3(PB11,PB10);

void setup() {
 Serial.begin(38400);
 Serial1.begin(38400);
 Serial2.begin(38400);
 Serial3.begin(38400);

}
void loop() {}

 

Feofan
Offline
Зарегистрирован: 28.05.2017
ОтЪ! Все поехало.
dimax Большое Спасибо!
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Новость:  сайт www.stm32duino.com поднялся.

Ну  и заодно продолжу тему парочкой своих скетчей из соседнего топика.

Частотометр на stm32f030f4p6. Программа использует недокументированный 32-битный таймер.

/* Частотометр прямого счёта на stm32f030f4p6. Измерительный вход PA0 или PA5 на выбор
точность +/- 1Герц. Максимальная измеряемая частота не менее, чем тактовая/3. 
*/

#define TIM2   ((TIM_TypeDef *) (APBPERIPH_BASE + 0x00000000UL))
void setup() {
Serial1.setRx(PA10); Serial1.setTx(PA9);
Serial1.begin(9600); 
RCC->AHBENR |= 1<<17;// enable clock: pioa
RCC->APB2ENR |=1<<11; //enable clock: tim1
RCC->APB1ENR |=3; //enable clock: tim2,3
GPIOA->MODER |= (1<<1)  ; //PA0  Alternate function mode
GPIOA->AFR[0] |= (1<<1); //af02 pa0                       
//или можно вход на PA5
//GPIOA->MODER |= (1<<11)  ; //PA5  Alternate function mode
//GPIOA->AFR[0] |= (1<<21); //pa5 af02 Mode                        
TIM2->SMCR= (1<<14)|(0<<12)|(5<<0);// ECE, ETPS:00 ,TS:000(TIM1),SMS:101 
TIM2->ARR=0xFFFFFFFF; //считать до максимума
TIM2->CR1|=(1<<0);//start timer2
uint16_t      psc=1;
uint32_t    tim_arr = F_CPU/1;// чтобы измерять менее 1 секунды добавить делитель
while ( (tim_arr/psc) > 65536) {psc++;} 
TIM1->PSC=psc-1;//
TIM1->ARR=(tim_arr/psc)-1;
TIM1->CR1=(1<<3)|(1<<2);//один импульс, без прерываний
TIM1->CR2=(1<<4);  //MMS:001 сигнал разрешения работы  таймеру2
TIM1->CR1|=(1<<0);
}

void loop() {
while (TIM1->CR1&1) {asm volatile("nop");   }
Serial1.println( (TIM2->CNT) );
TIM2->CNT=0;
TIM1->CR1|=(1<<0);
}

Следующий пример для  stm32f103c8t6 Генерация 4-х разных частот одним таймером. Зачем это нужно не знаю, но интересна сама возможность. 

/* Генерации одним таймером нескольких частот за счёт перепрограммирования 
 *  регистров сравнения в прерываниях. Выходы PA8,9,10,11 Частоты с данными параметрами
 *  549,36Hz 1098Hz 2197 Hz 4394Hz компилить в ардуине (аддон от STM) без UART и без USB
 */
uint16_t CCR1_Val = 32768;
uint16_t CCR2_Val = 16384;
uint16_t CCR3_Val = 8192;
uint16_t CCR4_Val = 4096;
void setup() {
HardwareTimer *MyTim = new HardwareTimer(TIM1);
RCC->APB2ENR|=(1<<11)|(1<<2); //tim1, gpioa clock enable
GPIOA->CRH&=~0xFFFF;
GPIOA->CRH|=0xBBBB; //PA8,9,10,11 output altfunc
TIM1->CCER=(1<<12)|(1<<8)|(1<<4)|(1<<0);//pin enable 
TIM1->CCMR1=(3<<12)|(3<<4);//toogle mode 
TIM1->CCMR2=(3<<12)|(3<<4);//toogle mode
TIM1->PSC=1;
TIM1->ARR=65535;
TIM1->CCR1=CCR1_Val;
TIM1->CCR2=CCR2_Val;
TIM1->CCR3=CCR3_Val;
TIM1->CCR4=CCR4_Val;
TIM1->BDTR=1<<14;//output enable
TIM1->CR1=1;
MyTim->attachInterrupt(1,tim1_ch1);
MyTim->attachInterrupt(2,tim1_ch2);
MyTim->attachInterrupt(3,tim1_ch3);
MyTim->attachInterrupt(4,tim1_ch4);
}
void tim1_ch1() {TIM1->CCR1+=CCR1_Val;}
void tim1_ch2() {TIM1->CCR2+=CCR2_Val;}
void tim1_ch3() {TIM1->CCR3+=CCR3_Val;}
void tim1_ch4() {TIM1->CCR4+=CCR4_Val;}

void loop(){}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Обнаружил проблему при работе через  SPI с  дисплеем ST7735 .

Загружаю один и тот-же проверочный  скетч в одной и той же версии ARDUINO IDE  с кларковским аддоном - время вывода на дисплей через SPI  -72 миллисекунды. А с STM-овским аддоном - 890 миллисекунд и хоть ты тресни, ничего не помогает  :((

Дополнено: по умолчанию частота клоков дисплея в stm-овском аддоне была 2,5МГц против 18МГц в кларковском. Сделал тоже 18МГц строчкой настройки дисплея  tft.setSPISpeed(18000000);   стало быстрей, но всё равно раза в 3 медленней чем скорость вывода в кларковском аддоне. Оказывается на этот счёт были вопросы на гитхабе и форуме, вот например.  В ответ Фредерик (автор stm-мовской библы) честно признался, цитата "Ядро Роджера является лучшим по производительности для F1 (использование DMA,...) Может быть, когда-нибудь это ядро окажется на том же уровне" Эта фраза написана в феврале 19-года, так что видимо устранение этой проблемы если и есть в его планах, то явно не в ближайших.

А тем временем аддон Роджера Кларка оказывается тоже не стоит на месте, обновляется, и что важно  появилась поддержка новой платы  F401ccu6 о которой говорилось во #2 посте.  Так что теперь большой вопрос -стоит ли переходить на stm-овский аддон окончательно и бесповоротно? :)

b707
Offline
Зарегистрирован: 26.05.2017

Подниму тему. В тему предыдущего сообщения. Димакс, не приходилось сравнивать скорость прямой записи в порт а двух аддонах?
Экспериментально измерил, что выполнение прямой записи в регистр в кларковском аддоне:
GPIOA->regs->BRR = BIT6
занимает 10 тактов контроллера. Не могу понять, много это или нет? В СТМовском аддоне не прикидывали?

a5021
Offline
Зарегистрирован: 07.07.2013

10 тактов, мне покажись, многовато, но вряд ли тут от адонов зависит. Скорее от компилятора и уровня оптимизации. Еще конвейер (prefetch unit) может свою лепту вносить.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

b707, похоже на правду, не сравнивал. Но думаю что разницы не будет. Аналогичное обсуждение кстати было в теме stm32 & Arduino IDE, я там даже ассемблером ноги дёргал для эксперимента   #237  там полный цикл ногодрыга прогонялся за 7 тактов МК, но это ещё без учёта предзагрузки  рабочих регистров. 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Какие 10 тактов?

Два такта:

void setup() {
   pinMode(PB12, OUTPUT);
   while(1) {
      GPIOB_BASE->BSRR = 0x00001000;
      GPIOB_BASE->BSRR = 0x10000000;
      GPIOB_BASE->BSRR = 0x00001000;
      GPIOB_BASE->BSRR = 0x10000000;
      GPIOB_BASE->BSRR = 0x00001000;
      GPIOB_BASE->BSRR = 0x10000000;
   }
}

void loop() {
}

// результаты:
// 1 - digitalWrite в setup ~1.2 us период (f=859)
// 2 - digitalWrite в loop ~1.2 us период
// 3 - ODR в loop ~55 ns период (18 MHz = 1/4 f)
// 4 - ODR в setup ~55 ns период
// 5 - BSRR в setup ~55 ns период
// 6 - BSRR в setup ~55 ns период
// 7 - bitband в loop ~165 ns период (6MHz = 1/12 f)
// 8 - bitband в setup ~165 ns период (6MHz = 1/12 f)

 

b707
Offline
Зарегистрирован: 26.05.2017

andriano пишет:

Какие 10 тактов?

Два такта:

какой аддон? СТМ?

nik182
Offline
Зарегистрирован: 04.05.2015

Простите, а при чем здесь аддон? Аддоны можно посравнивать когда верхние операторы используются типа ditalRead, а когда прямо пишем в порты на всех аддонах должно получиться одно и то же.

b707
Offline
Зарегистрирован: 26.05.2017

nik182 пишет:

Простите, а при чем здесь аддон? Аддоны можно посравнивать когда верхние операторы используются типа ditalRead, а когда прямо пишем в порты на всех аддонах должно получиться одно и то же.

при том, что ни запись

GPIOB_BASE->BSRR = 0x00001000;    // аддон СТМ

ни вот эта

GPIOA->regs->BRR = BIT6   // аддон Кларка

прямой записью в порт не являются. это все макросы разной степени кривизны

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

nik182 а вы посмотрите во что на AVR выливается команда прямой записи в порт DDRB=0 ...

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

b707 пишет:

GPIOB_BASE->BSRR = 0x00001000;    // аддон СТМ
GPIOA->regs->BRR = BIT6   // аддон Кларка

Это оба варианта для аддона Кларка :) У stm-ного короче:  GPIOB->BRR=

ps: Andriano не учитывал накладные расходы - запись в рабочие регистры адреса порта, и значений портов. А это как минимум ещё 3 команды по 2 такта каждая :)

b707
Offline
Зарегистрирован: 26.05.2017

dimax пишет:

ps: Andriano не учитывал накладные расходы - запись в рабочие регистры адреса порта, и значений портов. А это как минимум ещё 3 команды по 2 такта каждая :)

тогда непонятно, как у него получилось 18 МГц - выше, насколько я понимаю, дергать GPIO невозможно даже теоретически. с учетом того что частота тактирования шины freq/4

nik182
Offline
Зарегистрирован: 04.05.2015

b707 пишет:

при том, что ни запись

GPIOB_BASE->BSRR = 0x00001000;    // аддон СТМ

ни вот эта

GPIOA->regs->BRR = BIT6   // аддон Кларка

прямой записью в порт не являются. это все макросы разной степени кривизны

Вот тут Вы глубоко заблуждаетесь. Эти макросы описывают одно и тоже. Адрес регистра BRR. Как бы Вы не писали в ассемблере получите одно и тоже число, по адресу которого и будет отправлено BIT6 или 0x00001000; причём атомарно - т.е. за 1 такт:

9.1.2 Atomic bit set or reset

There is no need for the software to disable interrupts when programming the GPIOx_ODR at bit level: it is possible to modify only one or several bits in a single atomic APB2 write access. This is achieved by programming to ‘1’ the Bit Set/Reset Register (GPIOx_BSRR,or for reset only GPIOx_BRR) to select the bits you want to modify. The unselected bits will not be modified.
 
Хочу заметить, что  APB2 имеет частоту равную частоте ядра. Откуда Вы взяли "частота тактирования шины freq/4" ?
b707
Offline
Зарегистрирован: 26.05.2017

nik182 пишет:

Эти макросы описывают одно и тоже. Адрес регистра BRR. Как бы Вы не писали в ассемблере получите одно и тоже число, по адресу которого и будет отправлено BIT6 или 0x00001000; причём атомарно - т.е. за 1 такт:

что я имел в виду - макросы могут раскрыватся как непосредственно в адрес регистра, так и в некую конструкцию, вычисляющую его значение. Как пример, макрос BIT6 и 0x00100000 это, вообще говоря. не одно и то же, поскольку BIT6 в аддоне Кларка раскрывается в конструкцию (1 << 6) . которая сама по себе требует нескольких тактов для вычисления (в отсутсвии оптимизации, конечно)

поэтому разные макросы в разных аддонах могут требовать разное число тактов...

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

1 << 6 это константа скорее всего ...

b707
Offline
Зарегистрирован: 26.05.2017

Komandir пишет:

1 << 6 это константа скорее всего ...

 это как пример

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

b707, ну про шину Nic182 уже сказал. Так что и выходит: 2 такта поднять лапу, 2 опустить -  72e6/4= 18MHz, но это без учёта цикла. Если он нужен, то это плюс ещё 3 такта. Ну и накладные расходы на загрузку нужных данных в рабочие регистры. По идее если нужно просто поднять лапу, то надо дать всего три команды:

asm volatile (
  "ldr   R0, =0x40011010"  "\n\t" // положить сюда адрес PORTC->BSRR 
  "mov   R1, 0x2000"       "\n\t"  //положить сюда значение для BitSet PC13
  "str   R1, [R0]"         "\n\t"  // выполнить.
: : : );

 По 2 такта каждая, исходя из этого да, 10 тактов многовато. 

nik182
Offline
Зарегистрирован: 04.05.2015

На самом деле получается медленнее, потому есть ещё такты ожидания чтения флеша процессора. Вот если цикл программы загнать в оперативную память и работать из неё то получим максимальную скорость. 

b707
Offline
Зарегистрирован: 26.05.2017

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Пролистнул тему немного выше и, похоже, речь идет о том, с чем я столкнулся буквально на днях (т.е. почти месяцем позже, чем это было написано)

dimax пишет:

Обнаружил проблему при работе через  SPI с  дисплеем ST7735 .

Загружаю один и тот-же проверочный  скетч в одной и той же версии ARDUINO IDE  с кларковским аддоном - время вывода на дисплей через SPI  -72 миллисекунды. А с STM-овским аддоном - 890 миллисекунд и хоть ты тресни, ничего не помогает  :((

Если я правильно понял, речь идет не о прямой записи в порты, а об SPI, т.е. той прокладке, которая была написана для совместимости со стандартной ардуиновской библиотекой SPI. Я, правда, работал не с дисплеем, а с памятью (разрекламированной Петровичем PSRAM) и SD-картой.

Ну с картой там много всего, сектор читается что-то порядка 2.5 мс, т.е. по 5 мкс на байт, что на мой взгляд многовато. А с памятью - более прозрачно, там я взаимодействую не с драйвером SD, а напрямую с библиотекой SPI, которая, вроде бы, настроена на частоту 36 МГц, но реально работает так, как если бы было около 7 МГц. Т.е. один байт пишет/читает более 1 мкс.

Судя по логическому анализатору передача осуществляется побайтно с большим интервалом между байтами. Но это разобрать 24-МГц анализатором уже невозможно.

Собственно, я для себя сделал вывод, что нужно будет самостоятельно разбираться с STM-овским SPI, не надеясь на ардуиновскую реализацию.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

andriano пишет:

Судя по логическому анализатору передача осуществляется побайтно с большим интервалом между байтами. Но это разобрать 24-МГц анализатором уже невозможно.

Я тоже смотрел spi-клоки  осциллографом , и именно это наблюдал -огромные интервалы между пачками. В результате  пришлось вернуться обратно на кларковский аддон.. 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Я все-таки придерживаюсь точки зрения, что нужно отказываться от ардуиновской библиотеки и делать обмен по SPI ручками по дэйташиту. Вполне вероятно, что при наличии DMA побайтовый обмен сделан неоптимально на уровне железа, т.к. никому не нужен при наличии DMA. Ну, точнее, скорость от него не требуется.

Кстати, на мой взгляд, SPI не так уж сложно программируется по дэйташиту, так что думаю, именно это оптимальный путь - отказ от совместимости с ардуиновской библиотекой.

Sled
Offline
Зарегистрирован: 27.08.2017

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

Если сплошные подводные камни, то может чисто под STM пытаться писать? Заранее признателен!

b707
Offline
Зарегистрирован: 26.05.2017

Sled пишет:

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

"отчетики" я начальству пишу, а вам с какой стати? :)

тема как раз создана для сравнения аддонов - и в ней всего чуть более 50 сообщений, читайте