реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> STM32 отправка в USART по DMA в момент заполнения
Balabes
сообщение Aug 20 2014, 10:41
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 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;
}
Go to the top of the page
 
+Quote Post
scifi
сообщение Aug 20 2014, 11:20
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Вот так, разве нет?
Код
case 8:
{
    RXBuf = read_data_reg();
    uart_send_byte(RXBuf);
    STATE++;
    break;
}

Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 20 2014, 11:27
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 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;
Go to the top of the page
 
+Quote Post
Balabes
сообщение Aug 20 2014, 11:32
Сообщение #4


Участник
*

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



хочется что бы контроллер этим не занимался и данные отправлялись не тратя время, что бы контроллер забрал следующий байт из модема и ничего не потерял.
Go to the top of the page
 
+Quote Post
Integro
сообщение Aug 20 2014, 15:14
Сообщение #5


Частый гость
**

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



Цитата(Balabes @ Aug 20 2014, 14:32) *
хочется что бы контроллер этим не занимался и данные отправлялись не тратя время, что бы контроллер забрал следующий байт из модема и ничего не потерял.

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

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

Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 20 2014, 15:17
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



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

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

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

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


Ну или еще раз объясните какая у вас система, если я не смог правильно разгадать шарадуsm.gif
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Aug 20 2014, 22:25
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 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] - для короткого!
Go to the top of the page
 
+Quote Post
Balabes
сообщение Aug 21 2014, 05:09
Сообщение #8


Участник
*

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



модем это FX919 - и пока пытаюсь реализовать так называемый прозрачный режим, после 2х синхропосылок отправляю некоторые байты по одному непрерывно. а приняв их хочу выкинуть их в усарт. вот и хотелось бы что бы проц вынимал из модема новые байты и просто клал их куда-то а они дальше сами отправлялись что бы он успел взять все байты и не потерять, он же не сможет принять следующий байт пока я не достану этот. По скорости вроде запас есть, т.к. сам модем работает на 9600 (если кондюки и кварц сильно не врут) а усарт 19200. Так вот успеет ли f107 достать байт и положить его в усарт? когда передавал пакеты по 10\12\7 байт первые 10 принимал, но пока их отправлял второй и третий пакетик уже не успевал принять правильно (это было для тренировки, реализовывать решено начать именно с режима по байту). Пакеты будут позже.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 21 2014, 06:21
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



так у этого модема параллельная шина. В вашем проце есть экстернал мемори интерфейс из которого ДМА сможет забрать данные? По первому описанию 107 проца вроде как нет...

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

Если прием на прерываниях то в прерывании где вы забираете байт, сразу пихайте его на выход и всех делов, опять же нет шансов не успеть что-то забрать.
Go to the top of the page
 
+Quote Post
Balabes
сообщение Aug 21 2014, 07:03
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 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++;
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 21 2014, 07:44
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



а точно read_data_reg возвращает не хрень?
Может проблема не в отправке а в приеме?

Go to the top of the page
 
+Quote Post
Balabes
сообщение Aug 21 2014, 07:48
Сообщение #12


Участник
*

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



с чего бы ей 10 раз прислать что надо, а потом хрень?)
тем более что я делал прием трех пакетов и если их принять, а потом выкинуть в усарт то все нормально было
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 21 2014, 08:51
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



USART_SendSymbol
опубликуйте эту функцию...
Есть подозрение что там просто добавление данных в буфер, и отправка по прерыванию.
Go to the top of the page
 
+Quote Post
Balabes
сообщение Aug 21 2014, 09:40
Сообщение #14


Участник
*

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 21 2014, 10:50
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



мда... библиотеки это круто.

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

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

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


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


Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 07:53
Рейтинг@Mail.ru


Страница сгенерированна за 0.01545 секунд с 7
ELECTRONIX ©2004-2016