Перейти к содержанию
    

STM32 отправка в USART по DMA в момент заполнения

Здравствуйте!

Подскажите как реализовать отправку в усарт содержимое буффера как только в нем что то появится?

Допустим: есть 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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

так что

case 8:
    if(TX_BUF_READY) //готовы отправлять
      {
         if(read_data_reg(&Temp) == 0) //есть что отправлять
         UartSendByte(Temp);
      }
    STATE++;
    break;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Если под "потерял" понимается пропуск байта изза ожидания завершения отправки типо:

  while (USART_GetFlagStatus(DECT_UART, USART_FLAG_TC) == RESET);

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

 

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

 

 

Ну или еще раз объясните какая у вас система, если я не смог правильно разгадать шараду:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот работающий код. Скорости и форматы передачи не здесь - настраиваются ДО вызова stream_initialize.

Скорость передачи по COM должна быть больше скорости заполнения.

 

#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
[codebox] для длинного кода, [code] - для короткого!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

Если прием на прерываниях то в прерывании где вы забираете байт, сразу пихайте его на выход и всех делов, опять же нет шансов не успеть что-то забрать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

post-77442-1408604438_thumb.png

как видите вот так

RXBuf = read_data_reg();
USART_SendSymbol(USART2, RXBuf);
STATE++;

 

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

 

write_data_reg(outb);
outb = outb + 0x01;
write_command_reg(0x05);
STATE++;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а точно read_data_reg возвращает не хрень?

Может проблема не в отправке а в приеме?

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

с чего бы ей 10 раз прислать что надо, а потом хрень?)

тем более что я делал прием трех пакетов и если их принять, а потом выкинуть в усарт то все нормально было

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

USART_SendSymbol

опубликуйте эту функцию...

Есть подозрение что там просто добавление данных в буфер, и отправка по прерыванию.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

 

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

 

 

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

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...