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

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

VladislavS, все это есть. А отладчик, естественно, не нужен: чем бы он мне помог здесь?
Похоже, у меня какая-то кривая сборка arm-none-eabi, хотя эту качал с армовского сайта…
С double внутри sqrtf нагуглил, что она действительно просто вызывает обычный sqrt! Поэтому и делает преобразования туда-сюда.

Ладно, датчик я все равно спалил, так что, пока новый из Китая придет, у меня будет минимум месяц ☹
В любом случае, я понимаю, что если тупой обсчет данных (без сложных функций) длится аж пару десятков миллисекунд, если там еще на каждый пиксель по 5 (оказывается, даже 5 надо!) корней будет, оно вообще будет жутко тормозным. Надо мобильный тепловизор на F303 или F401 делать, их есть у меня. А для all-sky камеры я напрямую на I2C "апельсинки" датчики повешу.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

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

Сообщение jcxz »

А отладчик, естественно, не нужен: чем бы он мне помог здесь?
...
С double внутри sqrtf нагуглил, что она действительно просто вызывает обычный sqrt!
И сколько понадобилось потратить часов, чтобы выяснить это?
А с отладчиком это обнаруживается за минуту. :beer:

PS: Не удивлюсь если Вы и огонь добываете посредством трения двух палочек, а спички не признаёте. :)
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

И сколько понадобилось потратить часов, чтобы выяснить это?

Тупо листинг глянул.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

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

Сообщение НовыйДень »

А зависание МК тоже по листингу определил? :)))
Lum1noFor
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

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

Сообщение Lum1noFor »

Что-то я не так делаю, друзья. Та же фигня - бесконечное прыгание из прерывания USART1 в прерывание TIM4 и обратно. Где я не прав? Код прилагаю. Прерывание TIM4 имеет приоритет 4, прерывание USART1 имеет приоритет 5.

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

volatile uint8_t SymbolCount = 0;
volatile char ReceivedText[20];

void USART1_IRQHandler(void) {

   while (((USART1->SR & USART_SR_RXNE) >> USART_SR_RXNE_Pos) == 0); // Wait for "RX buffer not empty flag".

   ReceivedText[SymbolCount++] = USART1->DR;                                           // Read buffer to ReceivedText[] array.


      if (SymbolCount == 0) {                                      // If first symbol recieved, start "Time out" timer.
           TIM4->CNT = 0;
           TIM4->CR1 |= TIM_CR1_CEN;
      }

      if (SymbolCount < 10) {
         TIM4->CNT = 0;                                    
      } else {
         TIM4->CNT = 0;
         TIM4->CR1 &=~ TIM_CR1_CEN;
         SymbolCount = 0;
      }


}


void TIM4_IRQHandler(void) {

TIM4->SR    &=~ TIM_SR_UIF      ; // Clear TIM4 flag.

TIM4->CR1    &=~ TIM_CR1_CEN      ; // Disable TIM4.

USART_SendStr("Time out!")      ;

SymbolCount = 0               ; // Set SymbolCount to zero.

}
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

1. Таймер на какой период настроен?
2. Зачем ждать в прерывании USART_SR_RXNE, если в прерывание попадаем только когда он взведён? Раз других прерываний UART не разрешено, то весь этот while можно заменить просто USART1->SR;
3. Проверки SymbolCount переусложнены. Пока не принят последний символ обнуляем и запускаем, иначе стоп таймер. Всего одно условие.
4. Флаг таймера можно сбрасывать просто записью нуля в SR.
Lum1noFor
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

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

Сообщение Lum1noFor »

1. Таймер настроен на 60 миллисекунд.
2. Учту, спасибо!
3. Также учту.

Спасибо за ответ! Но Ваши замечания относятся, скорее, к производительности, чем к причине, почему у меня возникает такая ситуация. Нет никаких домыслов по этому поводу?
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Домыслы... Эха с той стороны нет? Так то криминала в коде не видно.

Точно только прерывание по переполнению включено?
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

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

Сообщение НовыйДень »

Таймер должен запускаться в режиме ОДНОКРАТНОГО!! счета. One-Pulse Mode. Иначе таймер будет каждые 60 мс срабатывать.
Если вы уже попали в прерывание UART, то не нужно ожидать флага RXNE, поскольку прерывание срабатывает именно по этому флагу. При условии, что вы конечно включили срабатывание по RXNE.
В прерывании нужно проверить флаг RNXE через if, причем вот так:

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

if((USART1->SR & USART_SR_RNXE) && (USART1->CR1 & USART_CR1_RXNEIE)) 
{
    // прочитать принятый байт из DR в буфер
    // перезапустить таймер таймаута
}

вторую проверку бита USART_CR1_RXNEIE можно не делать, если не планируется выключать этот запрос прерывания.
А всё остальное не нужно. А в прерывании таймера сбросить флаг этого прерывания и установить программный флаг превышения таймаута, а заодним и сбросить счетчик индекса приемного буфераю
Таймаут, как я понимаю, вы делаете для того, чтобы распознать прекращение передачи извне. Таким образом, срабатывание таймера таймаута будет автоматически разделять пакеты.

В строчке TIM4->SR &=~ TIM_SR_UIF значок & не нужен, потому что сброс бита производится записью в него 0, запись 1 не влияет. Поэтому, инвертированное значение бита TIM_SR_UIF достаточно.
И при однократном режиме таймер в прерывании остановится сам.
Последний раз редактировалось НовыйДень Вт май 24, 2022 22:04:43, всего редактировалось 4 раза.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

Полез переделывать USB на STM32F103, который у меня нахрапом (скопировав с F303) не вышел.
Обнаружил интересную фигню: при тех же флагах (за исключением относящихся к архитектуре) CFLAGS и LDFLAGS, F103 вешается на системных функциях (strlen и memcpy). Сделал свою реализацию strlen/memcpy — виснуть перестало! Остается найти, где я нарукожопил в кольцевом буфере, что на больших потоках данных подвисает (а F303 не подвисал — т.е. явно проблема с быстродействием → моим рукожопием).
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Lum1noFor
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

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

Сообщение Lum1noFor »

Таймаут, как я понимаю, вы делаете для того, чтобы распознать прекращение передачи извне. Таким образом, срабатывание таймера таймаута будет автоматически разделять пакеты.


Спасибо за ответ! Вы подали мне несколько идей, где может крыться ошибка. Задача таймаута в моем случае одна: если за отведенное время мы не получили все 10 символов команды, то выдавать ошибку компу. Если же мы получили все 10 символов, таймаут сработать не должен. Завтра доберусь до компа и проверю наши с Вами домыслы.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

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

if((USART1->SR & USART_SR_RNXE) && (USART1->CR1 & USART_CR1_RXNEIE)) 
Совершенно излишняя проверка, если вы не включаете другие прерывания USART (рассматриваемый случай) или не выключаете RXNE никогда (тоже наш случай). Лучше уж ошибки проверить, это хотя бы полезно.

Lum1noFor, One Pulse не обязательно, вы же его выключаете по срабатыванию. Проблема точно не тут, но с One Pulse можно убрать это выключение, так что, вполне разумно именно с ним.

СпойлерЯ бы вот так сделал

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

void USART1_IRQHandler(void)
{
  uint32_t sr = USART1->SR; 
  uint8_t data = USART1->DR;   
  if(sr & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE))
  {
    // Реакция на ошибку в приеме
  }
  else
  {
    // обработка принятых данных 
  } 
}
Lum1noFor
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

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

Сообщение Lum1noFor »

Ув. НовыйДень подал мне идею насильно сбрасывать флаг прерывания USART1 (в данном случае RXNE) в прерывании таймера таймаута. Тогда, возможно, возврата в предыдущее прерывание по стеку не будет. Нужно проверять.

Судя по моим мучениям с этой простейшей штукой, я подозреваю, что здесь что-то не совсем чисто: допустим, прерывание TIM4 сработало посередине выполнения кода прерывания USART1. Тогда, отработав, прерывание TIM4 должно отдать управление прерыванию USART1 В ТО ЖЕ МЕСТО (по стеку), ОТКУДА ОНО СРАБОТАЛО. Это касается главного цикла программы. Но здесь, судя по всему, прерывание USART1 ВСЕГДА начинается сначала, то есть с вектора прерывания. Не с той команды внутри прерывания, с которой оно было прервано, а всегда сначала. Поэтому надо каким-то образом "убрать" из стека это самое прерывание USART1, чтобы оно считалось уже выполненным на момент срабатывания TIM4. А когда сработает TIM4 - знает только сам TIM4 :). В общем, попробую.

В ПИКах от Микрочипа можно было просто отключить Nested Interrupts. Почему здесь нельзя - вопрос.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Сделать(оставить по умолчанию) приоритет одинаковый.
tonyk
Это не хвост, это антенна
Сообщения: 1305
Зарегистрирован: Вт ноя 19, 2019 06:10:18

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

Сообщение tonyk »

Судя по моим мучениям с этой простейшей штукой...

Сделай на IDLE и не мучайся. После этого и DMA прикручивается просто и логично. И таймер сэкономишь. Механизм IDLE как и RTO измеряет паузу в битах передаваемых данных, потому не зависит от скорости обмена в отличие от метода с таймером TIM.
Lum1noFor
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

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

Сообщение Lum1noFor »

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

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

void USART1_IRQHandler(void) {

   if (SymbolCount == 0) {
              TIM4->CNT = 0;
              TIM4->CR1 |= TIM_CR1_CEN;
   }

   ReceivedText[SymbolCount++] = USART1->DR;
}


void TIM4_IRQHandler(void) {

TIM4->SR &=~ TIM_SR_UIF;

TIM4->CR1 &=~ TIM_CR1_CEN;

USART_SendStr("Time out!"); // ПРОБЛЕМА ЗДЕСЬ!

SymbolCount = 0;

}


Если убрать строчку с передачей текста ошибки через USART1, все работает нормально. Все прерывания, кроме RXNE выключены. Код инициализации прерывания прикрепляю ниже.

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

#define USART_TX_ON (GPIOB->ODR |= GPIO_ODR_ODR5)
#define USART_TX_OFF (GPIOB->ODR &=~ GPIO_ODR_ODR5)

const Baudrate = 9600;

void USART1_Init(void) {
   
   GPIOA->CRH      &=~ GPIO_CRH_CNF9_0                        ; // PA9 as alternate funtion Push-Pull (TX). (CNF = "0b10").
   GPIOA->CRH       |=    GPIO_CRH_CNF9_1                        ;
GPIOA->CRH       |=  (GPIO_CRH_MODE9 | GPIO_CRH_MODE9)         ; // PA9 is OUTPUT, 50MHz max. (MODE = "0b11").

        GPIOA->CRH      &=~ GPIO_CRH_CNF10_0                     ; // PA10 as input with Pull-Up (RX) (CNF = "0b10").
   GPIOA->CRH       |=    GPIO_CRH_CNF10_1                     ;
   GPIOA->CRH       &=~  (GPIO_CRH_MODE10 | GPIO_CRH_MODE10)      ; // PA10 as Input.
   
   
   GPIOB->CRL       &=~ (GPIO_CRL_CNF5_0 | GPIO_CRL_CNF5_1)         ; // PB5 as output with Push-Pull (RX/TX). (CNF = "0b00").
   GPIOB->CRL       |=  (GPIO_CRL_MODE5_0 | GPIO_CRL_MODE5_1)      ; // PA5 is OUTPUT, 50MHz max. (MODE = "0b11").
   
   
   GPIOB->ODR      &=~   GPIO_ODR_ODR5                        ; // TX = 0;
   
   
   USART1->BRR     = SystemCoreClock/Baudrate;
   
   USART1->CR1    = 0;
   USART1->CR2    = 0;
   USART1->CR3    = 0;
   
   USART1->CR1      |=  USART_CR1_RXNEIE                     ; // Enable RX interrupt.
   USART1->CR1      &=~ USART_CR1_TXEIE                        ; // Disable TX interrupt.
   USART1->CR1      &=~ USART_CR1_IDLEIE                     ; // Disable Idle interrupt.
   USART1->CR1      &=~ USART_CR1_TCIE                        ; // Disable transmit complete interrupt.
   USART1->CR1      &=~ USART_CR1_PEIE                        ; // Disable PEIE interrupt.
   USART1->CR3      &=~ USART_CR3_CTSIE                        ; // Disable CTSIE interrupt.
   
   
   NVIC_SetPriority(USART1_IRQn, 5)                        ; // Set USART1 IRQ Priority.
   NVIC_EnableIRQ (USART1_IRQn)                           ;
   
   USART1->CR1      |=    USART_CR1_UE                        ; // Enable USART1.
   USART1->CR1      |=    USART_CR1_RE                        ; // Enable USART1 Reciever.
   USART1->CR1      |=    USART_CR1_TE                        ; // Enable USART1 Transmitter.
   
}



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

void USART_SendSymbol(uint8_t usymb) {

USART_TX_ON;

while (((USART1->SR & USART_SR_TXE) >> USART_SR_TXE_Pos) == 0); // Wait for TXE flag.

USART1->DR = usymb;             // Trancieve data.

while (((USART1->SR & USART_SR_TXE) >> USART_SR_TXE_Pos) == 0); // Wait for TXE flag.

Delay_us(1000);

USART_TX_OFF;

}



void USART_SendStr(char *ustr) {
     char *q = ustr;
     while (*q)
     {
        USART_SendSymbol(*q++);
     }
}



В чем может быть причина?
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

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

Сообщение WiseLord »

Миллисекундная задержка на каждый символ - итого, USART_SendStr() висит несколько миллисекунд в прерывании таймера. - как-то некрасиво
Lum1noFor
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

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

Сообщение Lum1noFor »

WiseLord писал(а):Миллисекундная задержка на каждый символ - итого, USART_SendStr() висит несколько миллисекунд в прерывании таймера. - как-то некрасиво


Согласен, но без нее у меня не получилось. У меня стоит конвертер USART -> RS485, и для его работы мне нужно переключать линию Read/Write. Соответственно, при передаче я подаю на линию Read/Write единицу, а в конце передачи я должен перевести ее обратно в 0. И если после окончания передачи я переведу линию Read/Write раньше, чем через 1 мс, передача идет криво. Переписал код вот так (теперь задержка всего одна):

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

void USART_SendSymbol(uint8_t usymb) {

while (((USART1->SR & USART_SR_TXE) >> USART_SR_TXE_Pos) == 0); // Wait for TXE flag.

USART1->DR = usymb;             // Trancieve data.

}



void USART_SendStr(char *ustr) {
     char *q = ustr;
    
     USART_TX_ON;
    
     while (*q)
     {
        USART_SendSymbol(*q++);
     }
    
     Delay_us(1000);
    
     USART_TX_OFF;
}
tonyk
Это не хвост, это антенна
Сообщения: 1305
Зарегистрирован: Вт ноя 19, 2019 06:10:18

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

Сообщение tonyk »

Lum1noFor писал(а):И если после окончания передачи я переведу линию Read/Write раньше, чем через 1 мс, передача идет криво

Открою тебе страшную тайну: у USART есть ещё флаги, кроме USART_SR_TXE, показывающие состояние передатчика. А ещё у USART есть ДВА регистра: один для загрузки передаваемого байта, а второй сдвиговый, содержимое которого выдаётся на ножку TX. Флаг USART_SR_TXE показывает тебе, что регистр для получения от тебя байта свободен, а вот окончание выдачи битиков в линию из второго регистра показывает флаг USART_SR_TC. Вот по прерыванию от него-то тебе и нужно переключать линию.

Это всё нарисовано в мурзилке у СТМ.

А ещё одна страшная тайна- это MAX13487...
Последний раз редактировалось tonyk Ср май 25, 2022 14:04:33, всего редактировалось 1 раз.
Lum1noFor
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

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

Сообщение Lum1noFor »

Lum1noFor писал(а):И если после окончания передачи я переведу линию Read/Write раньше, чем через 1 мс, передача идет криво

Открою тебе страшную тайну: у USART есть ещё флаги, кроме USART_SR_TXE, показывающие состояние передатчика. А ещё у USART есть ДВА регистра: один для загрузки передаваемого байта, а второй сдвиговый, содержимое которого выдаётся на ножку TX. Флаг USART_SR_TXE показывает тебе, что регистр для получения от тебя байта свободен, а вот окончание выдачи битиков в линию из второго регистра показывает флаг USART_SR_TC. Вот по прерыванию от него-то тебе и нужно переключать линию.

Это всё нарисовано в мурзилке у СТМ.



Исправил, спасибо за замечание. Но проблему с перекрывающимися прерываниями это не решает.

UPD:

Мое заключение о том, что после возврата из одного прерывания в другое по стеку, выполнение первого прерывания начинается сначала НЕВЕРНО - проверил. Все выполняется откуда надо. Чтобы не вводить людей в заблуждение.
Последний раз редактировалось Lum1noFor Ср май 25, 2022 14:17:59, всего редактировалось 1 раз.
Ответить

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