Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

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

Вс май 22, 2022 14:15:58

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

Ладно, датчик я все равно спалил, так что, пока новый из Китая придет, у меня будет минимум месяц ☹
В любом случае, я понимаю, что если тупой обсчет данных (без сложных функций) длится аж пару десятков миллисекунд, если там еще на каждый пиксель по 5 (оказывается, даже 5 надо!) корней будет, оно вообще будет жутко тормозным. Надо мобильный тепловизор на F303 или F401 делать, их есть у меня. А для all-sky камеры я напрямую на I2C "апельсинки" датчики повешу.

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

Вс май 22, 2022 15:43:03

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

PS: Не удивлюсь если Вы и огонь добываете посредством трения двух палочек, а спички не признаёте. :)

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

Вс май 22, 2022 17:27:04

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

Тупо листинг глянул.

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

Вс май 22, 2022 17:42:52

А зависание МК тоже по листингу определил? :)))

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

Вт май 24, 2022 20:46:57

Что-то я не так делаю, друзья. Та же фигня - бесконечное прыгание из прерывания 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.

}

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

Вт май 24, 2022 21:00:57

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

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

Вт май 24, 2022 21:20:53

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

Спасибо за ответ! Но Ваши замечания относятся, скорее, к производительности, чем к причине, почему у меня возникает такая ситуация. Нет никаких домыслов по этому поводу?

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

Вт май 24, 2022 21:24:47

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

Точно только прерывание по переполнению включено?

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

Вт май 24, 2022 21:40:41

Таймер должен запускаться в режиме ОДНОКРАТНОГО!! счета. 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 раз(а).

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

Вт май 24, 2022 21:42:30

Полез переделывать USB на STM32F103, который у меня нахрапом (скопировав с F303) не вышел.
Обнаружил интересную фигню: при тех же флагах (за исключением относящихся к архитектуре) CFLAGS и LDFLAGS, F103 вешается на системных функциях (strlen и memcpy). Сделал свою реализацию strlen/memcpy — виснуть перестало! Остается найти, где я нарукожопил в кольцевом буфере, что на больших потоках данных подвисает (а F303 не подвисал — т.е. явно проблема с быстродействием → моим рукожопием).

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

Вт май 24, 2022 22:07:42

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


Спасибо за ответ! Вы подали мне несколько идей, где может крыться ошибка. Задача таймаута в моем случае одна: если за отведенное время мы не получили все 10 символов команды, то выдавать ошибку компу. Если же мы получили все 10 символов, таймаут сработать не должен. Завтра доберусь до компа и проверю наши с Вами домыслы.

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

Вт май 24, 2022 22:32:39

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

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

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

Вт май 24, 2022 23:20:08

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

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

В ПИКах от Микрочипа можно было просто отключить Nested Interrupts. Почему здесь нельзя - вопрос.

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

Ср май 25, 2022 00:26:36

Сделать(оставить по умолчанию) приоритет одинаковый.

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

Ср май 25, 2022 06:49:00

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

Сделай на IDLE и не мучайся. После этого и DMA прикручивается просто и логично. И таймер сэкономишь. Механизм IDLE как и RTO измеряет паузу в битах передаваемых данных, потому не зависит от скорости обмена в отличие от метода с таймером TIM.

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

Ср май 25, 2022 09:08:00

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

Код:
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++);
     }
}



В чем может быть причина?

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

Ср май 25, 2022 11:05:09

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

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

Ср май 25, 2022 13:12:58

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;
}

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

Ср май 25, 2022 13:57:05

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

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

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

А ещё одна страшная тайна- это MAX13487...
Последний раз редактировалось tonyk Ср май 25, 2022 14:04:33, всего редактировалось 1 раз.

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

Ср май 25, 2022 14:03:48

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

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

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



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

UPD:

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