Вопрос может показаться нелепым, но я на нем застрял.
Если между сеансами передачи данных организовать хотя бы небольшую задержку, то проблем никаких нет. Но если по окончании одного сеанса необходимо тут же начать новый, то второй почему-то зависает. Сразу приходит мысль о том, что по окончании первого сеанса был некорректно закрыт канал, но ни один из вариантов не увенчался успехом. За основу был взят алгоритм из даташита
UM10360. LPC17xx. User manual:
Код
DMACC0CONFIGURATION_bit.H = 1; //any future DMA requests will be ignored
while (DMACC0CONFIGURATION_bit.A); // wait, while channel FIFO has any data
DMACC0CONFIGURATION_bit.E = 0; //channel 0 disabled
while (DMACENBLDCHNS & 0x1); //wait, while channel 0 is enabled
Но всевозможные очистки очереди запросов прерываний (DMACINTTCCLEAR), отключения DMA для UART'a (U1FCR), отключения каналов DMA (DMACCONFIGURATION = 0) и прочие не помогли.
На всякий случай приведу один из вариантов кода инициализации канала DMA:
Код
// Clear ALL DMA interrupt and error flag
DMACINTTCCLEAR = 0xFF;
DMACINTERRCLR = 0xFF;
DMACC0SRCADDR = 0x40010000;
DMACC0DESTADDR = (unsigned long)srcAddress;
DMACC0CONTROL = (size & 0x0FFF) //TransferSize
| (5 << 12) //Source burst size is 32 bit
| (5 << 15) //Destination burst size is 32 bit
| (0 << 18) //Source transfer width is 1 byte
| (0 << 21) //Destination transfer width is 1 byte
| (0 << 26) //Source address is NOT incremented
| (1 << 27) //Destination address is incremented
| 0x80000000; //The terminal count interrupt is enabled.
DMACCONFIGURATION = 0x01; // Enable DMA channels, little endian
DMACC0CONFIGURATION = (1 << 0) //CHANNEL 0 ENABLE
| (11 << 1) //Source peripheral is UART1 Rx
| (0 << 6) //Destination peripheral is memory
| (2 << 11) //Transfer type is "peripheral to memory"
| (1 << 14) //Error interrupts are NOT masked out
| (1 << 15) //Terminal count interrupts are NOT masked out
| (0 << 18);//Enable DMA requests
while(!(DMACENBLDCHNS));
DMACINTTCCLEAR = 0x0F;
Однако мне интересно прежде всего, как Вы инициализируете и заканчиваете организацию передачи по UART'у через DMA. В частности, какие регистры и в какой последовательности при этом задействуете, а какие инициализируете в начале программы и не трогаете при повторении инициализации очередного сеанса.
Ни в даташите, ни в интернете, ни в примерах ИАР'а я не нашел однозначного ответа. В частности, из даташита не понятно, для чего нужны регистры, указывающие состояние передачи до маскирования (DMA Raw Error Interrupt Status register и DMA Raw Terminal Count Status register). Ведь мы маскируем прерывания еще до начала сеанса и какая может быть передача до этого момента?
В качестве обработчика прерываний я использую обработчик из примера.
Код
DWORD regVal;
__enable_interrupt();
regVal = DMACINTTCSTATUS;
if ( regVal )
{
DMATCCnt++;
DMACINTTCCLEAR = regVal;
}
regVal = DMACINTERRSTAT;
if ( regVal )
{
DMAErrCnt++;
DMACINTERRCLR = regVal;
}
NVIC_ClrPend(NVIC_GP_DMA);
Вроде бы этого достаточно для определения окончания передачи, но судя по тому, что между передачами требуется задержка, о которой я писал в начале, складывается ощущение, что на этом передача не заканчивается.
Хотелось бы узнать, есть ли здесь какие-то "подводные камни". Может кто поделится секретом?