05.03.2014, 15:54
|
|
Прописка
Регистрация: 04.08.2006
Сообщений: 139
Сказал спасибо: 12
Сказали Спасибо 12 раз(а) в 11 сообщении(ях)
|
STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
Объясните, пожалуйста, как правильно работать с прерываниями Half Transfer, Transfer Complete? Я понимаю, что по очереди, т.е., пришло прерывание Half Transfer, начинаю в нем подготавливать/обрабатывать полученные данные. А за это время приходит прерывание Transfer Complete. И та же процедура в нем. Затем все по кругу.
Есть rxBuffer на восемь байт. Принимается строка через USART - 10 байт, (например: "1234567890"). Так вот, когда приходит прерывание Half Transfer, то в нем пришедшие данные располагаются таким образом - 90345678. Т.е., заполнился весь буфер целиком плюс последние два байта перезаписались поверх первых двух затерлись.
Я предполагал, что в первом прерывании в буфер попадает 1234. С ними работаю. Во втором прерывании - 5678. Теперь с этими работаю. Далее снова в первом - 0912 и так далее.
Каким образом прочитать первые байты?
Код:
|
#include "stm32f4xx.h"
#include "misc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_dma.h"
#include ‹stdio.h›
#define baudrate 9600
#define BUF_SIZE 8
unsigned char rxBuffer[BUF_SIZE];
/***********************************************/
void GPIO_Config(void);
void Usart_Config(void);
void DMA_Config(void);
void DMA1_Stream5_IRQHandler(void);
/************************************************** **********************************************/
void GPIO_Config(void)
{
GPIO_InitTypeDef porta;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
porta.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; // PA2 --› usart2_TX, PA3 --› usart2_RX
porta.GPIO_Mode = GPIO_Mode_AF;
porta.GPIO_OType = GPIO_OType_PP;
porta.GPIO_PuPd = GPIO_PuPd_NOPULL;
porta.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_Init(GPIOA, &porta);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); // GPIOA
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); // GPIOA
}
/************************************************** **********************************************/
// Конфигурация usart2
void Usart_Config(void)
{
USART_InitTypeDef usart2;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
USART_DeInit(USART2);
usart2.USART_BaudRate = baudrate;
usart2.USART_WordLength = USART_WordLength_8b;
usart2.USART_StopBits = USART_StopBits_1;
usart2.USART_Parity = USART_Parity_No;
usart2.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
usart2.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &usart2);
USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
USART_Cmd(USART2, ENABLE);
}
/************************************************** **********************************************/
void DMA_Config(void)
{
DMA_InitTypeDef dma1;
NVIC_InitTypeDef nvicdma1;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
DMA_DeInit(DMA1_Stream5);
dma1.DMA_Channel = DMA_Channel_4;
dma1.DMA_PeripheralBaseAddr = (uint32_t)&(USART2-›DR);
dma1.DMA_Memory0BaseAddr = (uint32_t)rxBuffer;
dma1.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma1.DMA_BufferSize = BUF_SIZE;
dma1.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma1.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma1.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma1.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma1.DMA_Mode = DMA_Mode_Circular; // Циклический прием данных
dma1.DMA_Priority = DMA_Priority_Low;
dma1.DMA_FIFOMode = DMA_FIFOMode_Disable;
dma1.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
dma1.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma1.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream5, &dma1);
DMA_ITConfig(DMA1_Stream5, DMA_IT_HT | DMA_IT_TC, ENABLE);
nvicdma1.NVIC_IRQChannel = DMA1_Stream5_IRQn;
nvicdma1.NVIC_IRQChannelPreemptionPriority = 0;
nvicdma1.NVIC_IRQChannelSubPriority = 0;
nvicdma1.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicdma1);
}
/************************************************** **********************************************/
void DMA1_Stream5_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) == SET) {
DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5);
}
/************************************************/
if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) == SET) {
DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5);
}
}
/************************************************** **********************************************/
int main(void)
{
GPIO_Config();
Usart_Config();
DMA_Config();
DMA_Cmd(DMA1_Stream5, ENABLE);
while(1) {
}
return 0;
} |
Последний раз редактировалось hubble; 06.03.2014 в 12:24.
|
|
|
|
05.03.2014, 19:01
|
|
Гражданин KAZUS.RU
Регистрация: 25.11.2010
Сообщений: 516
Сказал спасибо: 1
Сказали Спасибо 126 раз(а) в 109 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
как предисловие - stm32 - это не тот камень где uart+dma - хорошая идея
где настройки частот? до main() или вообще пропущены?
скорость uart? чем смотрели пропуск/переполнение приемного буфера?
если отладчиком - то привет, приехали.
и да, HT/TC должно работать именно так как вы описали
|
|
|
|
06.03.2014, 12:24
|
|
Прописка
Регистрация: 04.08.2006
Сообщений: 139
Сказал спасибо: 12
Сказали Спасибо 12 раз(а) в 11 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
Спасибо, что ответили. Уже разобрался.
Действительно, в Кейле пользуюсь отладчиком. Плата STM32F4Discovery.
На каком-то форуме нашел, что смотреть работу в прерываниях на железе, используя отладчик, не выйдет (а я-то раньше в Протеусе это делал даже в прерываниях). Что придется поизвращаться. Именно это и не получалось. В общем, немного переделав код, получилось посмотреть переменные.
|
|
|
|
06.03.2014, 14:47
|
|
Прописка
Регистрация: 04.08.2006
Сообщений: 139
Сказал спасибо: 12
Сказали Спасибо 12 раз(а) в 11 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
Появились еще несколько вопросов.
Сообщение от Hives
|
как предисловие - stm32 - это не тот камень где uart+dma - хорошая идея
|
Пока еще не знаю, почему это так, но кое-какие сомнения появляются. Как бы там ни было, но допустим работать приходится именно в этой связке: usart + dma.
Каким образом получить полностью все данные?
Если, допустим, получаем 7 байт при 8-ми байтном буфере: 1234567. За первое прерывание будет получено 1234, за второе ... ничего, т.к. его просто не будет. Вернее, может быть данные и далее будут приниматься, но мне необходимо сейчас их получить и поработать с ними.
Подскажите, каким образом такое можно реализовать (не привлекая прерывание по приему каждого символа)? Или это не правильный подход?
Последний раз редактировалось hubble; 06.03.2014 в 14:51.
|
|
|
|
06.03.2014, 16:44
|
|
Заблокирован
Регистрация: 21.01.2014
Сообщений: 589
Сказал спасибо: 7
Сказали Спасибо 267 раз(а) в 206 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
Вам нужно определиться: что значит все данные приняты и можно с ними работать?
1. Число байтов известно. Тогда кладём в ДМА это число и работаем как обсуждалось выше.
2. Число байтов неизвестно или может изменяться. Тогда признак конца, например, пауза в передаче, timeout. Тогда после приёма каждого байта в прерывании USART сбрасывать таймер. И как таймер переполнится - timeout, можно работать с данными.
3. Признак конца данных - спец.символ, например, 0xFF. Тогда анализировать каждый байт в прерывании USART на предмет окончания данных, а из данных исключить появление спец.символа, чтобы не было ложных срабатываний.
4 ...
Последний раз редактировалось Yurkin2014; 06.03.2014 в 16:47.
|
|
|
|
06.03.2014, 19:24
|
|
Почётный гражданин KAZUS.RU
Регистрация: 08.06.2008
Сообщений: 1,394
Сказал спасибо: 4
Сказали Спасибо 183 раз(а) в 167 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
На скорости 9600 использовать DMA ???
В STM32F0 - аппаратное прерывание по заданному байту есть. Там DMA хорошо использовать на больших скоростях, но тоже не во всех протоколах.
|
|
|
|
06.03.2014, 23:00
|
|
Гражданин KAZUS.RU
Регистрация: 25.11.2010
Сообщений: 516
Сказал спасибо: 1
Сказали Спасибо 126 раз(а) в 109 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
hubble а, собственно, чем не устраивает ловить каждый байт в прерывании?
обычное fifo берет ~30 тактов на прием байта - вполне шустро и +полный контроль над потоком
|
|
|
|
07.03.2014, 09:24
|
|
Частый гость
Регистрация: 25.03.2010
Адрес: Voronezh
Сообщений: 35
Сказал спасибо: 0
Сказали Спасибо 7 раз(а) в 7 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
Здравствуйте.
Здесь такое ощущение, что успевает заполнится весь буфер из 8 символов, но поскольку Вы передаете 10 символов, то последние 2 символа переписывают первые 2. Я думаю что здесь происходит следующее:
Вы попадаете в прерывание и останавливаетесь в отладчике, что бы посмотреть буфер. А dma в это время продолжает работать. Когда Вы смотрите содержимое - все уже принято и Вы имеете то что наблюдаете. Что бы посмотреть реальные данные, что были в буфере на момент HT прерывания, необходимо исключить задержку до просмотра. Скопируйте Ваш буфер в прерывании в другой буфер и уже после копирования поставьте точку останова. Тогда Вы увидите, что было в буфере в момент времени чуть чуть отстающий от выставления флага HT прерывания.
Последний раз редактировалось Oleg Galizin; 07.03.2014 в 09:27.
|
|
|
|
07.03.2014, 11:21
|
|
Прописка
Регистрация: 04.08.2006
Сообщений: 139
Сказал спасибо: 12
Сказали Спасибо 12 раз(а) в 11 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
Сообщение от Boba_spb
|
На скорости 9600 использовать DMA ???
|
Я для примера взял эту скорость. Скорости будут другие. Да и передаваться будет совсем не 10 байт. Такое количество было взято для наглядности.
Сообщение от Hives
|
hubble а, собственно, чем не устраивает ловить каждый байт в прерывании?
|
Нет, нет. Меня такой вариант вполне устроит, если не смогу разобраться с приемом, используя DMA. Именно так всегда и делал. Но понять-то его работу (DMA) мне надо. И прерываний в проекте будет несколько. Да, собственно говоря, и существует зачем-то ведь такая связка - USART + DMA. Как я полагаю, такой вопрос (как забрать/передать последние байты) может возникнуть и при использовании ADC + DMA, DAC + DMA и т.д. Хотя с ними не работал. И, поэтому, не уверен в этом.
Сообщение от Oleg Galizin
|
Здравствуйте.
Здесь такое ощущение, что успевает заполнится весь буфер из 8 символов, но поскольку Вы передаете 10 символов, то последние 2 символа переписывают первые 2. Я думаю что здесь происходит следующее:
Вы попадаете в прерывание и останавливаетесь в отладчике, что бы посмотреть буфер. А dma в это время продолжает работать. Когда Вы смотрите содержимое - все уже принято и Вы имеете то что наблюдаете. Что бы посмотреть реальные данные, что были в буфере на момент HT прерывания, необходимо исключить задержку до просмотра. Скопируйте Ваш буфер в прерывании в другой буфер и уже после копирования поставьте точку останова. Тогда Вы увидите, что было в буфере в момент времени чуть чуть отстающий от выставления флага HT прерывания.
|
Да, именно так все и происходит. Спасибо за участие. Но с этим вопросом уже разобрался. Понял, как можно просматривать.
Остался лишь тот вопрос, который в сообщении №4.
Пришло сообщение. Б ольшую его часть словил, а маленький кусочек в конце плюс контрольную сумму (например) нет. Вернее она в буфере лежит, но вот прерывания Half Transfer или Transfer Complete не наступили. Так как половина буфера или вторая половина еще не заполнились.
Последний раз редактировалось hubble; 07.03.2014 в 11:27.
|
|
|
|
07.03.2014, 17:58
|
|
Прохожий
Регистрация: 31.08.2010
Адрес: Красноярский край
Сообщений: 2
Сказал спасибо: 0
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: STM32F4xx. Прерывания Half Transfer, Transfer Complete. Не понятные моменты
Уважаемый, hubble.
В качестве решения вашей задачки предлагаю рассмотреть вариант использования двух буферов для приема данных по UART.
Для этого необходимо поток DMA настроить в режиме Double buffer mode – см. п.10.3.9 Reference manual RM0090 v.6. Настройка достаточно проста: в регистре DMA_SxCR необходимо установить бит DBM. В регистр DMA_SxM0AR занести адрес начала первого буфера. В регистр DMA_SxM1AR занести адрес начала второго буфера. Установить бит CT регистра DMA_SxCR в соответствии с тем, в какой буфер сначала будут записываться данные (лог. 0 – в буфер по адресу, указанному в DMA_SxM0AR, лог. 1 – по адресу DMA_SxM1AR). Прерывание DMA настроить по факту полного завершения передачи.
Процедура работы следующая:
1. Как только DMA выполнить заданное число пересылок (указанное в регистре DMA_SxNDTR) в буфер с номером CT, он переключит состояние бита CT и автоматически перейдет на запись данных в другой буфер. В это время возникнет прерывание по завершению пересылки данных (взведется бит TCIFx).
2. В прерывании Вы определяете путем чтения бита CT, с каким буфером сейчас работает DMA, и выполняете обработку полученных данных в другом буфере.
3. При необходимости, если обработка данных занимает времени больше, чем заполнение буфера, при входе в прерывание можно изменить адрес в регистре DMA_SxM0AR или DMA_SxM1AR (в зависимости от того, какой из регистров не используется), указав третий (четвертый, пятый и так далее) свободный буфер, на который в следующий раз переключится DMA.
У меня такой подход используется для работы с АЦП. Четыре буфера переключаются циклически для обеспечения сохранности данных во время занятости процессора.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 18:51.
|
|