|
STM32 отправка в USART по DMA в момент заполнения |
|
|
|
Aug 20 2014, 10:41
|
Участник

Группа: Участник
Сообщений: 66
Регистрация: 8-07-13
Пользователь №: 77 442

|
Здравствуйте! Подскажите как реализовать отправку в усарт содержимое буффера как только в нем что то появится? Допустим: есть 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; }
|
|
|
|
|
Aug 20 2014, 11:27
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
надо еще проверить что отправить можно и есть что отправлять, вдруг скорость входа данных быстрее скорости выхода или наоборот Так же просили ДМА, но в случае отправки 1 байта как появился, это смысла не имеет, запись 1 байта в буфер отправки гораздо быстрее чем настройка ДМА на передачу буфера. Вот если пакеты будут в много байт, то ДМА смысл имеет. На всякий случай замечу что речь идет про железный UART, который после помещения в него байта передает его на выход сам, не трогая проц. В случае программной эмуляции ДМА может быть оправдан, но там сложнее так что Код case 8: if(TX_BUF_READY) //готовы отправлять { if(read_data_reg(&Temp) == 0) //есть что отправлять UartSendByte(Temp); } STATE++; break;
|
|
|
|
|
Aug 20 2014, 11:32
|
Участник

Группа: Участник
Сообщений: 66
Регистрация: 8-07-13
Пользователь №: 77 442

|
хочется что бы контроллер этим не занимался и данные отправлялись не тратя время, что бы контроллер забрал следующий байт из модема и ничего не потерял.
|
|
|
|
|
Aug 20 2014, 15:14
|

Частый гость
 
Группа: Свой
Сообщений: 167
Регистрация: 25-12-09
Из: Минск
Пользователь №: 54 460

|
Цитата(Balabes @ Aug 20 2014, 14:32)  хочется что бы контроллер этим не занимался и данные отправлялись не тратя время, что бы контроллер забрал следующий байт из модема и ничего не потерял. Если под "потерял" понимается пропуск байта изза ожидания завершения отправки типо: Код while (USART_GetFlagStatus(DECT_UART, USART_FLAG_TC) == RESET); То в данном случае буфер лучше заполнять в прерывании приема данных, а в основной программе проверять кол-во байт в буфере и выплевывать их в уарт. В данном случае уже можно будет использовать ДМА, понятно если накопится соответствующее кол-во байт.
|
|
|
|
|
Aug 20 2014, 15:17
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
чтобы запустить ДМА грубо надо заполнить структуру, откуда, куда, сколько байт и так далее... Причем это делается не один раз а каждый раз при запуске. Это гораздо дольше чем считать 1 байт и положить его в передатчик. Если вы все равно попадает в 8 состояние где происходит проверка и забор байта, то вы сильно выиграете если сделаете без ДМА. Если то что приведено - это только схема, то тогда надо делать ДМА который по прерыванию готовы данные (данные от модема) берет их и кладет в буфер отправки. Данные от модема приходят по UART? если так то можно сделать ДМА их забирающие и перекладывающие в другой UART. Но встает вопрос скоростей, у STMов обычно нет FIFO на UARTах, и потому данные могут теряться или забиваться, если скорости входа - выхода не будут совпадать. В ДМА обычно есть цепочки, то есть отработав одну посылку он переключается на вторую, можно сделать посылки которые ссылаются друг на друга, и тогда эта схема будет работать вечно запуская сама себя. Если скорости разные, то имеет смысл сделать ДМА который собирает большое сообщение (если можно выделить пакет), и по окончанию сбора дернет вас прерыванием, в котором вы переложите этот принятый буфер в UART вторым ДМА, когда потери на настройку будут оправданы длинной посылкой. Ну или еще раз объясните какая у вас система, если я не смог правильно разгадать шараду
|
|
|
|
|
Aug 20 2014, 22:25
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Вот работающий код. Скорости и форматы передачи не здесь - настраиваются ДО вызова 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 */
}
Сообщение отредактировал IgorKossak - Aug 21 2014, 07:58
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!
|
|
|
|
|
Aug 21 2014, 05:09
|
Участник

Группа: Участник
Сообщений: 66
Регистрация: 8-07-13
Пользователь №: 77 442

|
модем это FX919 - и пока пытаюсь реализовать так называемый прозрачный режим, после 2х синхропосылок отправляю некоторые байты по одному непрерывно. а приняв их хочу выкинуть их в усарт. вот и хотелось бы что бы проц вынимал из модема новые байты и просто клал их куда-то а они дальше сами отправлялись что бы он успел взять все байты и не потерять, он же не сможет принять следующий байт пока я не достану этот. По скорости вроде запас есть, т.к. сам модем работает на 9600 (если кондюки и кварц сильно не врут) а усарт 19200. Так вот успеет ли f107 достать байт и положить его в усарт? когда передавал пакеты по 10\12\7 байт первые 10 принимал, но пока их отправлял второй и третий пакетик уже не успевал принять правильно (это было для тренировки, реализовывать решено начать именно с режима по байту). Пакеты будут позже.
|
|
|
|
|
Aug 21 2014, 07:03
|
Участник

Группа: Участник
Сообщений: 66
Регистрация: 8-07-13
Пользователь №: 77 442

|
как видите вот так Код RXBuf = read_data_reg(); USART_SendSymbol(USART2, RXBuf); STATE++; вот это некорректно принимает только до А нормально, потом хрень какая то. Код write_data_reg(outb); outb = outb + 0x01; write_command_reg(0x05); STATE++;
|
|
|
|
|
Aug 21 2014, 07:48
|
Участник

Группа: Участник
Сообщений: 66
Регистрация: 8-07-13
Пользователь №: 77 442

|
с чего бы ей 10 раз прислать что надо, а потом хрень?) тем более что я делал прием трех пакетов и если их принять, а потом выкинуть в усарт то все нормально было
|
|
|
|
|
Aug 21 2014, 09:40
|
Участник

Группа: Участник
Сообщений: 66
Регистрация: 8-07-13
Пользователь №: 77 442

|
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 все нормально.
Сообщение отредактировал Balabes - Aug 21 2014, 09:28
|
|
|
|
|
Aug 21 2014, 10:50
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
мда... библиотеки это круто.
то есть вместо взять регистр, выделить флаг, проверить на ноль, вы вызываете функцию в которой это делается, и проверяете результат ее работы...
USART_FLAG_TC - это случаем не флаг что передача закончена?
надо проверять не этот флаг, а флаг что приемник готов принять символ, ну и конечно делать это напрямую из регистра а не через долбанную функцию...
едем дальше. Какой бы ни был терминал, он не может повлиять на передатчик, более того терминал отображает только то что принял железный приемник компьютера или драйвер в случае usb - com. То есть смена терминала не может влиять на смену принимаемых данных. Ищите что вы еще изменили, может у вас приемник в режиме автодетекции скорости или что-то типа того?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|