STM32 новичку в ARM что к чему

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Опытный кот
Аватара пользователя
Сообщения: 819
Зарегистрирован: Вт окт 23, 2012 13:17:25
Откуда: Прокопьевск

Сообщение Oxford »

WiseLord если нужно только записать данные использовать надо ODR, если нужно изменить значение порта есть два путя
1. через read IDR/ODR-modify-write ODR
2. Атомарный write BSRR(установка/сброс) регистр. либо просто атомарный BRR(сброс)

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

BRR только сбрасывает.

если в переменной лежит число 0x55, вам еще подготовить его надо будет. Если не используется несколько потоков, с атомарным доступом не надо морочиться. Программируете стандартно.
Инженер R@D

Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Контактная информация:
Реклама
Мучитель микросхем
Сообщения: 413
Зарегистрирован: Ср янв 04, 2012 11:57:40
Откуда: Алчевск

Сообщение Sergi »

Проверил скорость вех вариантов.
BSRR победил как всегда :)) .

Код: Выделить всё

void lcd_send_cmd(uint8_t cmd)
{
    LCD_DC_L;
    LCD_WR_L;
 //GPIOB->ODR &=~0xff00;GPIOB->ODR |= (cmd<<8);	//88596 tics
   GPIOB->BSRR = 0xff000000 | (cmd<<8);	                //66660 tics
 //LCD = cmd;		                                                        //72593 tics
    LCD_WR_H;
		LCD_DC_H;
};
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Oxford",url="/forum/viewtopic.php?p=3757982#p3757982"]Если не используется несколько потоков, с атомарным доступом не надо морочиться.[/uquote]Кроме потоков есть ещё и прерывания.

[uquote="Oxford",url="/forum/viewtopic.php?p=3757982#p3757982"]Программируете стандартно.[/uquote]Через BSRR это и есть стандартно, ибо тупо быстрее, чем R-M-W ODR.
Опытный кот
Аватара пользователя
Сообщения: 819
Зарегистрирован: Вт окт 23, 2012 13:17:25
Откуда: Прокопьевск

Сообщение Oxford »

VladislavS есть переменная которая меняется скажем uint8_ t X, как будешь записывать значение в порт через BSRR? Покажи код.

Прерывания другая история, это все равно контроллируемый код и однопоточный.
Инженер R@D

Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

[uquote="Oxford",url="/forum/viewtopic.php?p=3758011#p3758011"]VladislavS есть переменная которая меняется скажем uint8_ t X, как будешь записывать значение в порт через BSRR?[/uquote]
Да элементарно: GPIOX->BSRR = 0xff0000 | X
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Контактная информация:
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Oxford",url="/forum/viewtopic.php?p=3758011#p3758011"]VladislavS есть переменная которая меняется скажем uint8_ t X, как будешь записывать значение в порт через BSRR? Покажи код.[/uquote]Ну, в отличии от Эдика, я парень хитрый. К тому же, ты решил поиграть на моём поле. :)
Код то будет простой.

Код: Выделить всё

uint8_t X = GPIOA->IDR;         // Сделаем чтобы X была переменной, а не константой
PinList<GpioB<0xFF00>> bus8bit; // Определим шину на старшие 8 бит GPIOB
bus8bit = X;                    // Запишем в неё данные
А вот во что это скомпилируется, это как раз и интересно. А вариантов тут может быть два.

1. На процессоре STM32F103 без байтового доступа к регистрам
Компилятор выберет вот такой метод и запишет через BSRR

Код: Выделить всё

  template<uint32_t PM=PinsMask>
  static void inline write(uint16_t data)
  {
    if constexpr (PM == 0xFFFF)
      base()->ODR = data;
    else
      base()->BSRR = (PM << 16) | (data & PM);
  }
Листинг

Код: Выделить всё

//uint8_t X = GPIOA->IDR;
        LDR.N    R1,??main_0      ;; 0x40010808
        LDR      R0,[R1, #+0]
//PinList<GpioB<0xFF00>> bus8bit; 
//bus8bit = X;    
        LSLS     R0,R0,#+24
        LSRS     R0,R0,#+16
        ORR      R0,R0,#0xFF000000
        STR      R0,[R1, #+1032]
2. На процессоре STM32F303 c байтовым доступом к регистрам
Компилятор выберет вот такой метод и запишет через ODR

Код: Выделить всё

template<uint32_t PM=PinsMask>
static void inline write(uint16_t data)
{   
  if constexpr (PM == 0xFFFF)
    base()->ODR = data;
  else if constexpr (PM == 0x00FF)
    *(volatile uint8_t*)&base()->ODR = data;
  else if constexpr (PM == 0xFF00)
    *((volatile uint8_t*)&base()->ODR + 1) = data >> 8;
  else
    base()->BSRR = (PM << 16) | (data & PM);
}
Листинг

Код: Выделить всё

//uint8_t X = GPIOA->IDR;
        LDR.N    R0,??main_0      ;; 0x48000010
        LDR      R1,[R0, #+0]
//PinList<GpioB<0xFF00>> bus8bit; 
//bus8bit = X;    
        STRB     R1,[R0, #+1029]
Ну вот как-то так.

[uquote="Oxford",url="/forum/viewtopic.php?p=3758011#p3758011"]Прерывания другая история, это все равно контроллируемый код и однопоточный.[/uquote]Хм. Если в основном цикле я делаю неатомарный доступ R-M-W к порту и из прерывания к этому же порту идёт обращение... То всё!
СпойлерКод можно было и короче написать. Но это неважно, результат тот же.

Код: Выделить всё

uint8_t X = GPIOA->IDR;
PinList<GpioB<0xFF00>>::write(X);
Добавлено after 4 hours 17 minutes 21 second:
Ну куда же вы все разбежались? Я ещё не показал коронный номер, которому меня Reflector научил. :)

Копируем младшие 8 бит порта в старшие 8 бит в обратном порядке: PB0->PB15, PB1->PB14, PB2->PB13, PB3->PB12, PB4->PB11, PB5->PB10, PB6->PB9 и PB7->PB8.

Код: Выделить всё

PinList<PB_7, PB_6, PB_5,  PB_4,  PB_3,  PB_2,  PB_1,  PB_0 > bus_low;
PinList<PB_8, PB_9, PB_10, PB_11, PB_12, PB_13, PB_14, PB_15> bus_high;
bus_high = bus_low;
//Листинг
        LDR.N    R1,??main_0      ;; 0x48000410
        LDRB     R0,[R1, #+0]
        RBIT     R0,R0
        LSRS     R0,R0,#+24
        STRB     R0,[R1, #+5]
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

А теперь сделайте этот же коронный номер на C, пожалуйста.

Ну и интересно, каковы накладные расходы на хранение такого рода списка пинов. То, что они быстро работают, мы уже поняли, но интересно, сколько flash/ram памяти на них уходит.
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Sergi",url="/forum/viewtopic.php?p=3758000#p3758000"]Проверил скорость вех вариантов.
BSRR победил как всегда :))[/uquote]
У тебя задействованы не все оптимизации, если данные, WR и DC будут на одном порту, то для кода

Код: Выделить всё

void lcd_send_cmd(uint8_t cmd)
{
	LCD_DC_L;
	LCD_WR_L;
	GPIOB->BSRR = 0xff000000 | (cmd << 8);
	LCD_WR_H;
	LCD_DC_H;
}

uint8_t data = GPIOB->IDR;
lcd_send_cmd(data);
получим
Спойлер

Код: Выделить всё

ldr r2, [pc, #536]
ldr r3, [r2, #16] 

lsls r3, r3, #8 
mov.w r0, #0x200000 
uxth r3, r3 
str r0, [r2, #24] 
orr.w r3, r3, #0xFF000000 
mov.w r4, #0x800000 
movs r0, #128 
mov.w r12, #32 
str r4, [r2, #24] 
str r3, [r2, #24] 
str r0, [r2, #24] 
str.w r12, [r2, #24]
Однако запись можно совместить и получить такой вариант:

Код: Выделить всё

using LCD_DC = PB5;
using LCD_WR = PB7;
using LCD_DATA = GpioB<0xFF00>;

void lcd_send_cmd(uint8_t cmd)
{
	PinList<LCD_DC, LCD_WR, LCD_DATA>::write(cmd);
	LCD_WR::set();
	LCD_DC::set();
}
Спойлер

Код: Выделить всё

ldr r2, [pc, #528]
ldr r3, [r2, #16] 

lsls r3, r3, #8 
uxth r3, r3 
orr.w r3, r3, #0xFF000000 
orr.w r3, r3, #0xA00000 
movs r0, #128	; 0x80 
mov.w r12, #32 
str r3, [r2, #24] 
str r0, [r2, #24] 
str.w r12, [r2, #24]
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="WiseLord",url="/forum/viewtopic.php?p=3758189#p3758189"]А теперь сделайте этот же коронный номер на C, пожалуйста.[/uquote]

Код: Выделить всё

*((volatile uint8_t *)&GPIOB->ODR +1) = (__RBIT(GPIOB->IDR)>>24);
[uquote="WiseLord",url="/forum/viewtopic.php?p=3758189#p3758189"]Ну и интересно, каковы накладные расходы на хранение такого рода списка пинов. То, что они быстро работают, мы уже поняли, но интересно, сколько flash/ram памяти на них уходит.[/uquote]Ноль целых, хрен десятых. Я же привёл листинг. Это ВСЁ!!! Они обрабатываются на этапе компиляции.
Последний раз редактировалось VladislavS Ср дек 18, 2019 15:19:47, всего редактировалось 1 раз.
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

А есть какой-нибудь репозиторий на github, чтобы взглянуть, как эти шаблоны реализованы?
Контактная информация:
Мучитель микросхем
Сообщения: 413
Зарегистрирован: Ср янв 04, 2012 11:57:40
Откуда: Алчевск

Сообщение Sergi »

2 Reflector
Я пишу на С и там с -O3 получается так

Код: Выделить всё

      136:     LCD_DC_L; 
0x08000AF4 4A08      LDR      r2,[pc,#32]  ; @0x08000B18
0x08000AF6 F04F7180  MOV      r1,#0x1000000
0x08000AFA 6011      STR      r1,[r2,#0x00]
   137:                 LCD_WR_L; 
0x08000AFC 104B      ASRS     r3,r1,#1
0x08000AFE 4907      LDR      r1,[pc,#28]  ; @0x08000B1C
0x08000B00 600B      STR      r3,[r1,#0x00]
   138:                 GPIOB->BSRR = 0xff000000 | (cmd<<8); 
0x08000B02 F04F437F  MOV      r3,#0xFF000000
0x08000B06 EA432000  ORR      r0,r3,r0,LSL #8
0x08000B0A 6008      STR      r0,[r1,#0x00]
   139:     LCD_WR_H; 
0x08000B0C 2080      MOVS     r0,#0x80
0x08000B0E 6008      STR      r0,[r1,#0x00]
   140:                 LCD_DC_H; 
0x08000B10 0040      LSLS     r0,r0,#1
0x08000B12 6010      STR      r0,[r2,#0x00]
Как написать на С Ваше выражение?
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Sergi",url="/forum/viewtopic.php?p=3758319#p3758319"]Как написать на С Ваше выражение?[/uquote]
Там по листингу видно, что вместо 0xFF00'0000 используется 0xFFA0'0000, т.е. дополнительно сбрасываются в 0 WR и DC. Будет одна запись в BSRR вместо трех.
Друг Кота
Аватара пользователя
Сообщения: 7026
Зарегистрирован: Сб янв 28, 2006 22:47:24

Сообщение Asmodey »

Какие страшные вещи вы тут обсуждаете, в теме для новичков. Аж мороз по коже...

У меня все проще, STM32F303BC стала не видна после случайной попытки изнасилования прошивкой для F103 из кейла дебагером ST-Link. Не видна не в утилите ST-Link, ни в IAR. При попытке приконнектится к микроконтроллеру вылезают сообщения об отсутствии целевого устройства. Это теперь навсегда или можно как-то исправить?

Попробовать через usart ее почистить? Но, вроде как для запуска загрузчика нужно ноги boot подтянуть и притянуть на плюс-минус питания? Reset обязательно нужно к чему-то подключить?

ПЫСЫ. До того МК определялся в утилите ST-Link как STM32F302/303. А после того как потыкался в него из кайла, космика и еще чего-то, пропал МК из виду. Есть еще микроконтроллеры, но перепаивать переходную плату, да потом снова запороть микроконтроллер очень не хотелось бы.
Последний раз редактировалось Asmodey Ср дек 18, 2019 22:28:37, всего редактировалось 2 раза.
Астролябия-сама меряет, было бы что мерять!!!
afz
Опытный кот
Аватара пользователя
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

Сообщение afz »

Попробуй запустить с нажатым Ресетом. Код чужой прошивки, естественно, работает неправильно и, похоже, отключает что-то из отладочных средств, из-за чего ST-link перестает работать. Запуск с Ресета позволит запустить ST-link, не выполнив ни одного байта из кода чужой прошивки.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Мучитель микросхем
Сообщения: 413
Зарегистрирован: Ср янв 04, 2012 11:57:40
Откуда: Алчевск

Сообщение Sergi »

Перенес ногу DC на порт В. Добавил линию задержки RCD для DC. Код сократился до

Код: Выделить всё


   136:                 GPIOB->BSRR = 0xff900000 | (cmd<<8);GPIOB->BSRR = 0x00000090; 
0x08000AF4 4903      LDR      r1,[pc,#12]  ; @0x08000B04
0x08000AF6 EB012100  ADD      r1,r1,r0,LSL #8
0x08000AFA 4803      LDR      r0,[pc,#12]  ; @0x08000B08
0x08000AFC 6001      STR      r1,[r0,#0x00]
0x08000AFE 2190      MOVS     r1,#0x90
0x08000B00 6001      STR      r1,[r0,#0x00]
Получился самый быстрый код.
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Sergi",url="/forum/viewtopic.php?p=3758809#p3758809"]Получился самый быстрый код.[/uquote]
Значение DC скорее всего защелкивается вместе с данными по фронту WR, если DC и WR устанавливать одновременно, то мы опять возвращаемся к тому с чего начали, т.е. неопределенному поведению. Поменяется частота или длина проводов и уже может начать глючить, хотя весьма вероятно оно изредка глючит уже сейчас.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

То есть, если что и задерживать, то как раз WR.

Зато как быстро глючит :)
Мучитель микросхем
Сообщения: 413
Зарегистрирован: Ср янв 04, 2012 11:57:40
Откуда: Алчевск

Сообщение Sergi »

DC устанавливается с задержкой 22 наносекунды от WR. Сбрасывается через 2. Визуально помех пока не обнаружил.Будут помехи - разделю установку.
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Sergi",url="/forum/viewtopic.php?p=3758834#p3758834"]DC устанавливается с задержкой 22 наносекунды от WR. Сбрасывается через 2. Визуально помех пока не обнаружил.Будут помехи - разделю установку.[/uquote]
Насколько совмещенная установка влияет на производительность учитывая, что в основном на дисплей передаются данные для которых дергать DC не нужно? Думаю разницы практически не будет. Например, выводим символ 8*12, это 192 байта данных цветов плюс 4 или 8 данных координат окна, итого 200 байт против 3 для работы с регистрами которые будут на треть медленнее. Заметное замедление будет наблюдаться только если задавать координаты для каждой выводимой точки, иначе разница должны быть меньше процента.
Последний раз редактировалось Reflector Чт дек 19, 2019 13:18:16, всего редактировалось 1 раз.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Что-то тут не так. Надо первой командой устанавливать: WR=0, нужное значение DC и Data(Cmd). Второй командой ставить WR=1, а остальное пусть остаётся старое. Так без всяких линий задержки должно работать.
Ответить

Вернуться в «ARM»