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

Re: stm32f4 usart+DMA

Вс фев 06, 2022 13:05:12

Код:
uint8_t len =* string ;

Это вообще что? Получение указателя на строку в переменную размером 1 байт?
Вам бы самому что-ль си подучить. :dont_know:

Re: stm32f4 usart+DMA

Вс фев 06, 2022 13:08:09

Протеус.Не отладчик.У меня не IAR.Cubeide

Выбросите. И поставьте хотя бы Keil. Бесплатная версия может отлаживать приложение размером до 32кБ.
Зато в нём можно подсмотреть содержимое регистров, пройтись по памяти, заглянуть в значения переменных, пройтись по программе в пошаговом режиме, чтобы понять, что делает код, который ВЫ написали.

Вообще, я начинал с ассемблера под AVR. Ну так получилось.
И моим первым проектом была отладочная плата для контроллера. Кусок текстолита, ZIF сокет, куча светодиодов на портах, и гнёзда для подключения, затем... затем прошло много времени и я взялся за более продвинутый чип ATMega1284p, который по началу тоже был замучан на ассемблере. Уже после я взялся за Си. Так что мне страшно смотреть на Ваш код.

Отладочная плата тогда выглядела как-то так:
Спойлер
20140106_160528.jpg
Дичь, но работало. Сама печатная плата - готовая.
(103.75 KiB) Скачиваний: 29


Добавлено after 1 minute 47 seconds:
Код:
uint8_t len =* string ;

Это вообще что? Получение указателя на строку в переменную размером 1 байт?
Вам бы самому что-ль си подучить. :dont_know:

Ох, простите, я забыл знак [Sarcasm] из IT Crowd.

Re: stm32f4 usart+DMA

Вс фев 06, 2022 17:07:12

А сколько стоит что бы снять ограничение кода?.

Добавлено after 1 minute 12 seconds:
Если есть оганичение кода .Нет смысла всем этим заниматся.

Re: stm32f4 usart+DMA

Пн фев 07, 2022 06:54:13

А сколько стоит что бы снять ограничение кода?.

Добавлено after 1 minute 12 seconds:
Если есть оганичение кода .Нет смысла всем этим заниматся.

Вас в Гугле забанили?
https://ru.farnell.com/keil/mdk-arm-es- ... dp/3107107
Цифровая доставка
Скачать в течение 3 рабочих дней
Этот товар не подлежит отмене и возврату
3 192,00 €


Либо бесплатно на всем известных сайтах.
Йо-хо-хо! [SFX: He's a pirate]
Публиковать ссылки на последние никто не будет, они и так известны.

Re: stm32f4 usart+DMA

Пн фев 07, 2022 07:19:10

Бесплатно это какк.С ограничением кода?

Re: stm32f4 usart+DMA

Пн фев 07, 2022 07:56:00

Бесплатно это даром :)

Такими темпами 32К вы достигнете чуть позже чем никогда.

Re: stm32f4 usart+DMA

Пн фев 07, 2022 08:03:06

Добавить вещественное число вот и будет 32 кбайта.

Re: stm32f4 usart+DMA

Пн фев 07, 2022 08:48:09

С дуру и хрен сломать можно.

Re: stm32f4 usart+DMA

Пн фев 07, 2022 11:21:08

Мой код занимает...
Код:
Building RAM: ./Build/KeyBrain.elf
   text    data     bss     dec     hex filename
  41740      20   85052  126812   1ef5c ./Build/KeyBrain.elf

Включая работу с сетью, DHCP, UART, сканер отпечатка пальцев, NTP, Telnet (хотя реализация топорная, но работает), FATFS + SDIO, FreeRTOS, и некоторое количество массивов с данными.
Так что расслабьтесь, небольшой проект 32кБ не займёт.

Другой проект:
Код:
:~/MCU_Proj/STM32F030-EEPROM$ make
Compiling: startup_stm32f030x8.s
Compiling: system_stm32f0xx.c
Compiling: main.c
Compiling: diskio.c
Compiling: ff.c
Compiling: uSD_SPI.c
Building: ./debug/ee_rw.elf
   text    data     bss     dec     hex filename
  21568    1260    2776   25604    6404 ./debug/ee_rw.elf

LCD + FatFS + SPI uSD + Кнопки + чтение-запись внешней EEPROM, парсер/экспортер Intel HEX. Меню на обратных вызовах (кое-где крайне костыльная реализация, но работает).
Чуть меньше 22кБ.

И это компилируется не Keil'овским компилятором, а обычным arm-none-eabi-gcc, хотя и с оптимизацией -Os.


[offtop]Я бы порекомендовал скачать eclipse, но его нужно настраивать под контроллер, искать .svd файлы, настраивать отладчик... муторно. У меня вообще make + gcc + gdb и в некоторых случаях отладка в том самом тормозном eclipse.[/offtop]

Re: stm32f4 usart+DMA

Пн фев 07, 2022 17:43:55

Я не спец.Ассемблер я не изучал.Он конечно лучше.Места меньше занимает.Но ассемблер это не моё.Тогда я буду всю жизнь программировать.Я не профи.

Re: stm32f4 usart+DMA

Пн фев 21, 2022 18:31:13

Вернемся к нашим буферам.

За основу был взят код передачи AlanDrakes с не большой переделкой, что бы действительно можно было использовать произвольный размер буфера
Спойлерсам код
Код:
volatile uint8_t DMA_STATE=0; // Флаг работы DMA
volatile uint32_t tty0_TX_POS=0; // Указатель позиции записи в буфер
volatile uint32_t tty0_WR_POS=0; // Указатель позиции чтения из буфера (DMA)
volatile uint8_t tty0_TX_BUF[32]={0}; // Размер буфера равным степени двойки, минимум 2

#define BUF_MASK    (sizeof(tty0_TX_BUF)-1)

volatile uint32_t len_WR_POS;
volatile uint32_t poz_WR_POS;

#define DMA_tty0_TX_ACTIVE 1

void DMA1_Channel4_IRQHandler(){
    if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx
        DMA1->IFCR = DMA_IFCR_CTCIF4; // clear TC flag
        DMA1_Channel4->CCR &= ~DMA_CCR1_EN;   // Отключаем поток DM
      
        DMA_STATE &= ~DMA_tty0_TX_ACTIVE;

        while(len_WR_POS--){
         poz_WR_POS--;
           tty0_TX_BUF[poz_WR_POS & BUF_MASK]=0;
        }
        tty0_ActivateDMA();
    }
}

void tty0_ActivateDMA(void) {
   uint32_t CurrWrPos = tty0_WR_POS;
   uint32_t DataToSend;
   uint32_t mask = tty0_TX_POS & BUF_MASK;
   uint32_t curr = CurrWrPos & BUF_MASK;
   DataToSend = 0;
   if(!(DMA_STATE & DMA_tty0_TX_ACTIVE)) {
      DMA1_Channel4->CCR &= ~DMA_CCR1_EN;   // Отключаем поток DMA
      if (tty0_TX_POS != CurrWrPos) {
         // Если не совпадает - значит, данные есть. Или малый шанс на переполнение буфера.
         DMA1_Channel4->CMAR = (uint32_t)&(tty0_TX_BUF[mask]);
         if ((mask) < (curr)) {
            // Нет перехода через конец буфера
            DataToSend = (CurrWrPos - tty0_TX_POS);
            tty0_TX_POS = CurrWrPos;
         } else {
            // Нужно сделать кольцо.
            DataToSend = (sizeof(tty0_TX_BUF) - (mask));
            tty0_TX_POS += DataToSend;
         };

         len_WR_POS = DataToSend;
         poz_WR_POS = (tty0_TX_POS & BUF_MASK);

         DMA1_Channel4->CNDTR = DataToSend;
         USART1->SR = ~(USART_SR_TC);
         // И только ПОСЛЕ этого включаем его. Да, странность. Но иначе он уходит в ошибку.
         DMA1_Channel4->CCR |= DMA_CCR1_EN;
         DMA_STATE |= DMA_tty0_TX_ACTIVE;
      };
   };   // Если активен - сработает при вызове события завершения обмена.
};

// Принимаем СТРОКУ символов с нуль-терминатором.
void console_put(const char *text) {
   while(*text) {
      // Пока не нуль-терминатор
     while(tty0_TX_BUF[tty0_WR_POS & BUF_MASK]) { };   // цикл ожидания с проверкой на \0
      tty0_TX_BUF[tty0_WR_POS & BUF_MASK] = *text;      // Копируем данные в буфер
      text++;                  // Сдвигаем указатель текста.
      tty0_WR_POS++;               // Сдвигаем указатель на 1 байт дальше.
      if((tty0_WR_POS & BUF_MASK) == 0) tty0_ActivateDMA();
   };
   // Запускаем.
   tty0_ActivateDMA();
};
Кому надо, можете оптимизировать
Ну а теперь тесты
Спойлерсам тестовый код
Код:
   uint32_t start = DWT->CYCCNT;
   SEND("\r\n");
   printu(ms_tick);
   SEND("\r\n");
   SEND("\r\nSystem Frequency: ");
   printu(SystemCoreClock);
   SEND(" MHz \r\n");

   SEND("\r\n STM32F100RB USART DMA-tx !!! 31");
   SEND("\r\n STM32F100RB USART DMA-tx !!! 32");
   SEND("\r\n STM32F100RB USART DMA-tx !!! 33");

   SEND("\r\n");
   printu(ms_tick);
   SEND("\r\n");

   uint32_t end = DWT->CYCCNT;

   delay_ms(2000);

    SEND("\r\nstart-end = ");
    printu(end - start);
    SEND("\r\n");

    delay_ms(2000);

    uint32_t start_h = DWT->CYCCNT;
   SEND("Hello, world!\r\n");
   uint32_t end_h = DWT->CYCCNT;

   delay_ms(2000);

    SEND("\r\nstart_h-end_h = ");
    printu(end_h - start_h);
    SEND("\r\n");

    delay_ms(4000);

    uint32_t start_m = DWT->CYCCNT;
    SEND("... строка длиною 627 символов ...");
   uint32_t end_m = DWT->CYCCNT;

   delay_ms(2000);

    SEND("\r\nstart_m-end_m = ");
    printu(end_m - start_m);
    SEND("\r\n");
картинка
Изображение
В коде AlanDrakes при размере буфера в 256, было выведено последние 256 символов 627 символьной строки.
Всего отправлено до моего теста 857 символов.

В моем тесте отправляется 2596 символов, вот код моего теста
Код:
#define BUFFER_SIZE 512
volatile uint16_t Buffer[BUFFER_SIZE]={0};

void test (void){
   SEND("\r\n");
   printu(ms_tick);
   SEND("\r\n");

   for (uint16_t i = 1000; i<(1000+BUFFER_SIZE); i++){
      Buffer[i-1000] = i;
   }

    SEND("\r\n");
   printu(ms_tick);
   SEND("\r\n");

   for (uint16_t i = 0; i<BUFFER_SIZE; i++){
      printu(Buffer[i]);
      SEND(" ");
   }
   SEND("\r\n");

    SEND("\r\n");
   printu(ms_tick);
   SEND("\r\n");
}
и подсчитано затраченное время в милли секундах.
Пока что другой реализации я не видел.

Усе, с передачей закончили, переходим к приему.

Re: stm32f4 usart+DMA

Пн фев 21, 2022 19:08:42

В коде AlanDrakes при размере буфера в 256, было выведено последние 256 символов 627 символьной строки.

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

А у меня в проектах используется минимум 2к буфер под передачу, поскольку время от времени запись в него происходит крайне интенсивно.
В частности, лог первичной инициализации может занимать почти весь буфер.
В железке с кристаллом по больше - буфер передачи уже 4к.

Правда, рядом с буфером экрана в ~38кБ он смотрится мелковато.

Re: stm32f4 usart+DMA

Вт фев 22, 2022 21:41:56

AlanDrakes писал(а):Фактически, в буфер данные были положены, но их затёрло свежими. И это нормально для кольцевого буфера.
Нет, это не нормально, только представьте, что было бы с жестким диском компа или еще с чем.

Добавлено after 1 hour 13 minutes 11 seconds:
Переходим к приему.
За основу был взят код приема AlanDrakes с не большой переделкой
Спойлерсам код
Код:
#define MAX_DMA_BUFFERS_COUNT 64
char BoxCon_RX_BUF[MAX_DMA_BUFFERS_COUNT]={0};
volatile uint8_t DMA_BUF_START[MAX_DMA_BUFFERS_COUNT]={0};
volatile uint8_t DMA_BUF_END[MAX_DMA_BUFFERS_COUNT]={0};
volatile uint8_t DMA_CURR_WR_BUF = 0;
char buff[MAX_DMA_BUFFERS_COUNT] = {0};
Код:
void USART1_IRQHandler(){
    if (USART1->SR & USART_SR_IDLE) {
       (void)USART1->DR;      // Очистка флага IDLE. Мне лично кажется такой подход странным.
      static uint32_t DMA_BUF_START_LAST = 0; //    Устранен Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
       if ((sizeof(BoxCon_RX_BUF) - DMA1_Channel5->CNDTR) != DMA_BUF_START_LAST) {
          DMA_BUF_START[DMA_CURR_WR_BUF] = DMA_BUF_START_LAST;
          DMA_BUF_START_LAST = (sizeof(BoxCon_RX_BUF) - DMA1_Channel5->CNDTR);
          DMA_BUF_END[DMA_CURR_WR_BUF] = DMA_BUF_START_LAST;
          DMA_CURR_WR_BUF++;
          if (DMA_CURR_WR_BUF >= (MAX_DMA_BUFFERS_COUNT-1)) { DMA_CURR_WR_BUF = 0; };
       };
    }
}
Код:
    while(1)
    {      static uint8_t DMA_CURR_RD_BUF = 0;      // Устранен Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
         while (DMA_CURR_RD_BUF != DMA_CURR_WR_BUF) {
                uint8_t b_start = DMA_BUF_START[DMA_CURR_RD_BUF];   // Копируем позиции начала
                uint8_t b_end = DMA_BUF_END[DMA_CURR_RD_BUF];      // И конца буфера
                // Переводим на следующий (но не проверяем его данные)
                DMA_CURR_RD_BUF++;
                if (DMA_CURR_RD_BUF >= (MAX_DMA_BUFFERS_COUNT-1)) DMA_CURR_RD_BUF = 0;

                // сборка команды
                uint8_t len_buff = strlen(buff); // определяем длину

                if(b_start < b_end) {
                  uint32_t len = b_end-b_start;
                  if((len_buff+len)>(MAX_DMA_BUFFERS_COUNT-2)) len_buff=0;
                  memcpy(&buff[len_buff],&BoxCon_RX_BUF[b_start],len);
                  buff[len_buff+len]=0;
                  }

                  if(b_start > b_end) {
                  uint32_t len = MAX_DMA_BUFFERS_COUNT-b_start;
                  memcpy(&buff[len_buff],&BoxCon_RX_BUF[b_start],len);
                  memcpy(&buff[len],BoxCon_RX_BUF,b_end);
                  buff[len_buff+len+b_end]=0;
                  }
                  
                  len_buff = strlen(buff)-1; // определяем длину
               
               // если BkSp - сдвигаем назад
                  if((buff[len_buff] == 0x08)|| (buff[len_buff] == 0x7f)){
                  // стираем символ
                     // но не левее начала буфера
                     if(len_buff > 0) buff[len_buff-1]=0; else buff[len_buff]=0;
                     }

                  // если Enter - ввод закончен
                  if(((buff[len_buff] == '\n') || (buff[len_buff] == '\r'))) {
                     flag=1; buff[len_buff]=0; // стираем символ Enter, заменяем концом строки \0
                  }
             }
библиотека microrl оказалась слишком заумной
свою написал
Код:
static bool respcmp(char *s, const char  *resp)
{
   while(*resp)
      if(*resp++ != *s++) return false;
   return true;
}

static uint32_t my_atoi(char *str)
{
   int result = 0;

   if ('0'>*str || *str>'9')
   {
      str++;
   }
   while (*str != '\0')
   {
      if ('0'> *str || *str>'9')
         break;
      else
         result = result * 10 + (*str++ - '0');
   }
   return result;
}
Код:
      // поиск обработчика
      if (flag) {
        if (respcmp(buff, "LED ON")) {
          GPIOC - > ODR |= GPIO_Pin_9;
          SEND("\r\nLED ON\r\n");
        }
        if (respcmp(buff, "LED OFF")) {
          GPIOC - > ODR &= ~GPIO_Pin_9;
          SEND("\r\nLED OFF\r\n");
        }
        if (respcmp(buff, "B")) {
          GPIOC - > ODR |= GPIO_Pin_8;
          SEND("\r\nLED blue ON\r\n");
        }
        if (respcmp(buff, "S")) {
          GPIOC - > ODR &= ~GPIO_Pin_8;
          SEND("\r\nLED blue OFF\r\n");
        }
        if (respcmp(buff, "TOGGLE")) {
          GPIOC - > ODR ^= GPIO_Pin_9;
        }
        if (respcmp(buff, "PRINT")) {
          SEND("\r\nPRINT= ");
          printu(main_p);
          SEND("\r\n");
        }
        if (respcmp(buff, "COUNT=")) {
          main_p = my_atoi(buff + sizeof("COUNT=") - 1);
        }
        //if (!strcmp (buff, "LED ON")) { GPIOC->ODR |= GPIO_Pin_9; SEND("\r\nLED ON\r\n"); }
        //if (!strcmp (buff, "LED OFF")) { GPIOC->ODR &= ~GPIO_Pin_9; SEND("\r\nLED OFF\r\n"); }
        //if (!strcmp (buff, "TOGGLE")) { GPIOC->ODR ^= GPIO_Pin_9; }
        //sscanf(buff, "COUNT=%lu", &main_p);
        //if (!strcmp (buff, "B")) { GPIOC->ODR |= GPIO_Pin_8; SEND("\r\nLED blue ON\r\n"); }
        //if (!strcmp (buff, "S")) { GPIOC->ODR &= ~GPIO_Pin_8; SEND("\r\nLED blue OFF\r\n"); }
        buff[0] = 0;
        flag = 0;
        SEND("\nCMD > ");
      }
    } //while(1)
Что в итоге имеем:
-прерывание по IDLE
-поддерживается как по символьсный ввод, так и отправка строки по нажатию клавиши "Ввод"
-примитивное редактирование при помощи клавиши backspace
Длина команды ограничена 64 символами, учитывая нажатие клавиши backspace

Можете оптимизировать, или предлагать свои варианты.

Re: stm32f4 usart+DMA

Ср фев 23, 2022 06:16:38

AlanDrakes писал(а):Фактически, в буфер данные были положены, но их затёрло свежими. И это нормально для кольцевого буфера.
Нет, это не нормально, только представьте, что было бы с жестким диском компа или еще с чем.

Ну так если не следить за свободным местом - то нормально =]
Где-то в другой версии кода, была проверка на наползание указателей друг на друга. Там в цикле записи процессор отправлялся в сон до следующего прерывания. Собственно, костыль.

Re: stm32f4 usart+DMA

Ср фев 23, 2022 08:21:54

AlanDrakes писал(а):Собственно, костыль.
Опять же подходим к тому условию - если есть куча свободной оперативки. Вот f030 мне не хватило оперативки, а хочется не большой выигрыш, пусть и маленький, но выигрыш.
И опять же, с этим костылем 100% гарантия что все выведется, а не затрется часть.
Ответить