Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 отправка в USART по DMA в момент заполнения
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Balabes
Здравствуйте!
Подскажите как реализовать отправку в усарт содержимое буффера как только в нем что то появится?
Допустим: есть uint8_t RXBuf, и как только в него записывается байт, надо переслать его по усарту.
Код
case 5:
{
        write_command_reg(0x05);
    STATE++;
    break;
}
case 6:
{
    if ( GPIO_ReadInputDataBit(GPIOA, IRQN) == 0) STATE++;
    break;
}
case 7:
{
    StatusReg = read_status_reg();
    if ((StatusReg & 0xD0) == 0xC0) STATE++;
    break;
}
case 8:
{
    RXBuf = read_data_reg();
    STATE++;
    break;
}
case 9:
{
    STATE = 5;
    break;
}
scifi
Вот так, разве нет?
Код
case 8:
{
    RXBuf = read_data_reg();
    uart_send_byte(RXBuf);
    STATE++;
    break;
}

Golikov A.
надо еще проверить что отправить можно и есть что отправлять, вдруг скорость входа данных быстрее скорости выхода или наоборот

Так же просили ДМА, но в случае отправки 1 байта как появился, это смысла не имеет, запись 1 байта в буфер отправки гораздо быстрее чем настройка ДМА на передачу буфера. Вот если пакеты будут в много байт, то ДМА смысл имеет. На всякий случай замечу что речь идет про железный UART, который после помещения в него байта передает его на выход сам, не трогая проц. В случае программной эмуляции ДМА может быть оправдан, но там сложнее

так что
Код
case 8:
    if(TX_BUF_READY) //готовы отправлять
      {
         if(read_data_reg(&Temp) == 0) //есть что отправлять
         UartSendByte(Temp);
      }
    STATE++;
    break;
Balabes
хочется что бы контроллер этим не занимался и данные отправлялись не тратя время, что бы контроллер забрал следующий байт из модема и ничего не потерял.
Integro
Цитата(Balabes @ Aug 20 2014, 14:32) *
хочется что бы контроллер этим не занимался и данные отправлялись не тратя время, что бы контроллер забрал следующий байт из модема и ничего не потерял.

Если под "потерял" понимается пропуск байта изза ожидания завершения отправки типо:
Код
  while (USART_GetFlagStatus(DECT_UART, USART_FLAG_TC) == RESET);

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

Golikov A.
чтобы запустить ДМА грубо надо заполнить структуру, откуда, куда, сколько байт и так далее... Причем это делается не один раз а каждый раз при запуске. Это гораздо дольше чем считать 1 байт и положить его в передатчик. Если вы все равно попадает в 8 состояние где происходит проверка и забор байта, то вы сильно выиграете если сделаете без ДМА.

Если то что приведено - это только схема, то тогда надо делать ДМА который по прерыванию готовы данные (данные от модема) берет их и кладет в буфер отправки. Данные от модема приходят по UART? если так то можно сделать ДМА их забирающие и перекладывающие в другой UART. Но встает вопрос скоростей, у STMов обычно нет FIFO на UARTах, и потому данные могут теряться или забиваться, если скорости входа - выхода не будут совпадать.

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

Если скорости разные, то имеет смысл сделать ДМА который собирает большое сообщение (если можно выделить пакет), и по окончанию сбора дернет вас прерыванием, в котором вы переложите этот принятый буфер в UART вторым ДМА, когда потери на настройку будут оправданы длинной посылкой.


Ну или еще раз объясните какая у вас система, если я не смог правильно разгадать шарадуsm.gif
Genadi Zawidowski
Вот работающий код. Скорости и форматы передачи не здесь - настраиваются ДО вызова stream_initialize.
Скорость передачи по COM должна быть больше скорости заполнения.

CODE
#define DMAUSART1BUFFSIZE8 128

static uint_fast8_t txbuffphase;
static unsigned txbufflevel;
static uint8_t txbuff [2] [DMAUSART1BUFFSIZE8];

void stream_putchar(uint_fast8_t c)
{
txbuff [txbuffphase] [txbufflevel] = c;
if (++ txbufflevel >= DMAUSART1BUFFSIZE8)
{
DMA2->HIFCR = DMA_HIFCR_CTCIF7; // сбросил флаг от Stream7 - DMA готово начинать с начала
// Запуск передачи заполненного буфера
DMA2_Stream7->M0AR = (uint32_t) & txbuff [txbuffphase] [0];
DMA2_Stream7->CR |= DMA_SxCR_EN; // перезапуск DMA
// Буфер заполнился - переключаемся на следующий буфер
txbuffphase = ! txbuffphase;
txbufflevel = 0;
}
}

// Инициализация DMA по передаче USART1
void stream_initialize(void)
{

/* USART1_TX - Stream7, Channel4 */
/* DMA для передачи по USART1 */
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; // включил DMA2
__DSB();

DMA2_Stream7->PAR = (uint32_t) & USART1->DR;
DMA2_Stream7->FCR &= ~ DMA_SxFCR_DMDIS; // use direct mode
DMA2_Stream7->CR =
(0 * DMA_SxCR_MBURST_0) | // 0: single transfer
(0 * DMA_SxCR_PBURST_0) | // 0: single transfer
(4 * DMA_SxCR_CHSEL_0) | //канал 4
(1 * DMA_SxCR_DIR_0) | //направление - память - периферия
(1 * DMA_SxCR_MINC) | //инкремент памяти
(0 * DMA_SxCR_MSIZE_0) | //длина в памяти - 8 bit
(0 * DMA_SxCR_PSIZE_0) | //длина в USART_DR - 8 bit
(0 * DMA_SxCR_CIRC) | //циклический режим не требуется при DBM
(2 * DMA_SxCR_PL_0) |
(0 * DMA_SxCR_CT) | // M0AR selected
(0 * DMA_SxCR_DBM) | // double buffer mode seelcted
0;

DMA2_Stream7->NDTR = (DMA2_Stream7->NDTR & ~ DMA_SxNDT) |
(DMAUSART1BUFFSIZE8 * DMA_SxNDT_0) |
0;

USART1->CR3 |= USART_CR3_DMAT; /*!< DMA Enable Transmitter */


}
Balabes
модем это FX919 - и пока пытаюсь реализовать так называемый прозрачный режим, после 2х синхропосылок отправляю некоторые байты по одному непрерывно. а приняв их хочу выкинуть их в усарт. вот и хотелось бы что бы проц вынимал из модема новые байты и просто клал их куда-то а они дальше сами отправлялись что бы он успел взять все байты и не потерять, он же не сможет принять следующий байт пока я не достану этот. По скорости вроде запас есть, т.к. сам модем работает на 9600 (если кондюки и кварц сильно не врут) а усарт 19200. Так вот успеет ли f107 достать байт и положить его в усарт? когда передавал пакеты по 10\12\7 байт первые 10 принимал, но пока их отправлял второй и третий пакетик уже не успевал принять правильно (это было для тренировки, реализовывать решено начать именно с режима по байту). Пакеты будут позже.
Golikov A.
так у этого модема параллельная шина. В вашем проце есть экстернал мемори интерфейс из которого ДМА сможет забрать данные? По первому описанию 107 проца вроде как нет...

не очень понятно как при входной 9600 вы не могли успеть отправить на 19200. Прием полингом был сделан? Вам надо считать байт и сразу его положить одним тактом на выход. Так как входная скорость сильно меньше, выходной передатчик не может забиться, если работает. Вы же не используете управление потоком, правда?

Если прием на прерываниях то в прерывании где вы забираете байт, сразу пихайте его на выход и всех делов, опять же нет шансов не успеть что-то забрать.
Balabes
Нажмите для просмотра прикрепленного файла
как видите вот так
Код
RXBuf = read_data_reg();
USART_SendSymbol(USART2, RXBuf);
STATE++;


вот это некорректно принимает только до А нормально, потом хрень какая то.

Код
write_data_reg(outb);
outb = outb + 0x01;
write_command_reg(0x05);
STATE++;
Golikov A.
а точно read_data_reg возвращает не хрень?
Может проблема не в отправке а в приеме?

Balabes
с чего бы ей 10 раз прислать что надо, а потом хрень?)
тем более что я делал прием трех пакетов и если их принять, а потом выкинуть в усарт то все нормально было
Golikov A.
USART_SendSymbol
опубликуйте эту функцию...
Есть подозрение что там просто добавление данных в буфер, и отправка по прерыванию.
Balabes
void USART_SendSymbol(USART_TypeDef *USARTx, uint8_t data)
{
while((USART_GetFlagStatus(USARTx, USART_FLAG_TC)) == RESET);
USART_SendData(USARTx, data);
}

и

USART2->DR = RXBuf

Аналогичные результаты дает.
и даже на скоростях 115200 и 256000 тоже самое, попробую другой терминал

на 115200 в Putty все нормально.
Golikov A.
мда... библиотеки это круто.

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

USART_FLAG_TC - это случаем не флаг что передача закончена?

надо проверять не этот флаг, а флаг что приемник готов принять символ, ну и конечно делать это напрямую из регистра а не через долбанную функцию...


едем дальше. Какой бы ни был терминал, он не может повлиять на передатчик, более того терминал отображает только то что принял железный приемник компьютера или драйвер в случае usb - com. То есть смена терминала не может влиять на смену принимаемых данных. Ищите что вы еще изменили, может у вас приемник в режиме автодетекции скорости или что-то типа того?


Integro
Цитата(Golikov A. @ Aug 21 2014, 13:50) *
надо проверять не этот флаг, а флаг что приемник готов принять символ, ну и конечно делать это напрямую из регистра а не через долбанную функцию...


Все правильно сделал, перед тем как отправить символ проверяет готов ли передатчик его отправить(флаг, передача завершена).
Непонятно к чему это:
Код
USART2->DR = RXBuf

Где это используется? Здесь вы привели реализацию USART_SendData?

Golikov A.
я конечно наизусть не помню все реализации уартов у STM. Но в большинстве тех что я помню флаги
передача завершена и приемник передатчика пуст - это разные флаги.
И очередной байт можно и нужно отправлять ни когда послали прошлый, а когда приемник передатчика готов принять новый байт.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.