Суть дела в следующем. Допустим, буду читать из флэш по 100 байт. Для этого надо отправить на флэш 105 байт: 5 байт команды и 100 байт фиктивной записи.
Сначала я повесил прием на 2 канал DMA, а запись во флэш реализовал прямо в цикле for:
Код
uint8_t tx_buf[105]; //отсюда пишем во флэш, первые 5 байт - команда
uint8_t rx_buf[105]; //сюда DMA положит прочитанное
void read()
{
//настройка DMA на прием по 2 каналу
//по окончании приема 105 байт сработает прерывание IRQ_RX()
init_DMA_RX();
UART2_SSR2_RIE = 1; //разрешить прерывание по чтению
//запись 105 байт
FLASH_CS = FLASH_ON; //установить CS
for(uint16_t i=0; i<105; ++i)
{
while (UART2_SSR2_TDRE == 0); //жду освобождения регистра передачи
TRD2 = tx_buf[i]; //отправляю байт на флэш
}
FLASH_CS = FLASH_OFF; //снять CS
}
void IRQ_RX()
{
//сюда придем по завершению приема
//здесь выполняем всякие служебные вещи, чистим флаги и тд
//и повторное чтение в заисивмости от условия
if(/*условие*/)
read();
}
uint8_t rx_buf[105]; //сюда DMA положит прочитанное
void read()
{
//настройка DMA на прием по 2 каналу
//по окончании приема 105 байт сработает прерывание IRQ_RX()
init_DMA_RX();
UART2_SSR2_RIE = 1; //разрешить прерывание по чтению
//запись 105 байт
FLASH_CS = FLASH_ON; //установить CS
for(uint16_t i=0; i<105; ++i)
{
while (UART2_SSR2_TDRE == 0); //жду освобождения регистра передачи
TRD2 = tx_buf[i]; //отправляю байт на флэш
}
FLASH_CS = FLASH_OFF; //снять CS
}
void IRQ_RX()
{
//сюда придем по завершению приема
//здесь выполняем всякие служебные вещи, чистим флаги и тд
//и повторное чтение в заисивмости от условия
if(/*условие*/)
read();
}
Такой сценарий нормально работает. И при одиночном и при повторном вызове read() в rx_buf лежат валидные данные: 5 байт 0xFF и 100 байт из флэш
Но писать через for долго. Поэтому передачу tx_buf я тоже повесил на канал DMA:
Код
void read()
{
//настройка DMA на прием по 2 каналу
//по окончании приема 105 байт сработает прерывание IRQ_RX()
init_DMA_RX();
UART2_SSR2_RIE = 1; //разрешить прерыване по чтению
//настройка DMA на передачу по 3 каналу
//по окончании передачи 105 байт сработает прерывание IRQ_TX()
init_DMA_TX();
UART2_SSR2_TIE = 1; //разрешить прерывание по чтению
FLASH_CS = FLASH_ON; //установить CS
}
void IRQ_TX()
{
//сюда придем по завершению приема
//здесь выполняем всякие служебные вещи, чистим флаги и тд
//и снимаем CS
FLASH_CS = FLASH_OFF;
}
void IRQ_RX()
{
/*...*/
if(/*условие*/)
read();
}
{
//настройка DMA на прием по 2 каналу
//по окончании приема 105 байт сработает прерывание IRQ_RX()
init_DMA_RX();
UART2_SSR2_RIE = 1; //разрешить прерыване по чтению
//настройка DMA на передачу по 3 каналу
//по окончании передачи 105 байт сработает прерывание IRQ_TX()
init_DMA_TX();
UART2_SSR2_TIE = 1; //разрешить прерывание по чтению
FLASH_CS = FLASH_ON; //установить CS
}
void IRQ_TX()
{
//сюда придем по завершению приема
//здесь выполняем всякие служебные вещи, чистим флаги и тд
//и снимаем CS
FLASH_CS = FLASH_OFF;
}
void IRQ_RX()
{
/*...*/
if(/*условие*/)
read();
}
И вот этот сценарий дает сбой. Проблема в том, что в какой-то момент устанавливается в 1 флаг переполнения ORE USART`а.
Соответственно, в rx_buf по окончанию приема лежат невалидные данные. Обычно в конце буфера какая-то чушь, иногда в начале или вообще весь буфер бред.
Бывает и такое, что первый вызов read() дает корректные данные, но второй всегда невалидные.
Момент выставления ORE в единицу уловить невозможно, я так и не выявил зависимости. Что я делаю не так, в чем может быть проблема?