Hi,
I've got a problem with DMA transfers from/to eUSCI UART on MSP430FR5739 rev H mcu. Finally it should be more complicated transmission, but when the DMA problem appeared I had cut nearly 99% firmware looking for its source. With no results.
Now my program has only initialization of eUSCI in standard UART mode (8 bit, 1START, 1STOP, 19200 baud) and DMA init (ch1 - single repeated, size 5, IRQ after complete, for RX data; ch2 - single, size 5, for TX data). In the main loop I toggle one pin only.
I suspect the following should happen:
- 1. other device send 5 bytes (rq)
- 2. msp receive this packet with dma
- 3. IRQ from dma-ch1 should occur; here I start TX with dma-ch2 (6 bytes) by write to TXBUF
- 4. other device receive 6 bytes (ack).
All the points above should run in loop but... msp after receive less than 5 bytes hangs. Sometimes it can answer with correct packets but only a few times. When I stop cpu after it hangs it has in DMA registers values indicating that channel 1 (rx) is still busy (DMA1SZ = 1, 2 or 3). Furthermore flag UCRXIFG in UCA0IFG was set.
The polling interval is about 0.5 sec.
I tried speed up clocks but with no results. Now the base is MCLK running from DCO at 24MHz and ACLK running from XT1 at 14.7456MHz. I checked errata notes but with dma is (until now) problem in debug mode only. Of course I tried everything with and without debugger.
There is the program:
int _system_pre_init(void){
WDTCTL = WDTPW + WDTHOLD;
LED_PORT_OUT &= ~(LED_1|LED_2|LED_3);
LED_PORT_DIR |= (LED_1|LED_2|LED_3);
PJSEL0 |= (BIT4|BIT5);
CSCTL0_H = 0xA5;
CSCTL1 |= DCORSEL + DCOFSEL0 + DCOFSEL1;// Wybranie źródeł clocków
// ACLK = XT1; SMCLK = VLO; MCLK = DCO;
CSCTL2 = (SELA_0 | SELS_1 | SELM_3);
CSCTL3 = (ACLK_DIV | DIVS_0 | DIVM_0);
CSCTL4 = (XT1DRIVE_1 | XTS | XT1OFF);
CSCTL4 &= ~XT1OFF;
do {
CSCTL5 &= ~XT1OFFG;
SFRIFG1 &= ~OFIFG;
} while (SFRIFG1&OFIFG);
return 1;
}
void main(void){
init(data.sysRx, data.sysTx, SYS_BUF_SIZE, SYS_SPEED_DEF);
__bis_SR_register(GIE);
while (1){
if (++w == 100000) { w=0;
_led_power_on();
_wdi_pulse();
_led_power_off();
}
}
}
static void init(volatile void *rx, volatile void *tx, unsigned int size, unsigned long baud){
volatile unsigned char *ptr = rx;
unsigned long n;
// Configure UART pins
P2DIR &= ~(BIT0 + BIT1);
P2SEL0 &= ~(BIT0 + BIT1);
TX_PIN_ENABLE;
P2SEL1 |= BIT1; // RX pin enable
...
dma1Init(rx);
dma2Init(tx);
// Configure UART 0
UCA0CTLW0 = UCSWRST;
UCA0CTLW0 |= UCMODE_0 | UCSSEL__ACLK;
n = OSC/baud;
if (n >= 16) {
UCA0BRW = n/16;
UCA0MCTLW = UCOS16;
} else {
UCA0BRW = n;
UCA0MCTLW = 0;
}
UCA0CTL1 &= ~UCSWRST; // release from reset
dma1Start(5);
}
#pragma vector=DMA_VECTOR
__interrupt void _dma_isr(void){
switch(__even_in_range(DMAIV,8)){
case DMAIV_NONE: break; // No Interrupt
case DMAIV_DMA0IFG: break; // DMA0IFG
case DMAIV_DMA1IFG:
dma2Start(5);
UCA0TXBUF = 0x05;
break; // DMA1IFG
case DMAIV_DMA2IFG:
break; // DMA2IFG
}
}
void dma1Init(volatile void * dest){
DMA1SZ = 0;
DMACTL0 |= DMA1TSEL__UCA0RXIFG;
DMACTL4 |= DMARMWDIS;
__data16_write_addr((unsigned short)&DMA1SA,(unsigned long) &UCA0RXBUF);
__data16_write_addr((unsigned short)&DMA1DA,(unsigned long) dest);
DMA1CTL = (DMADT_4 | DMADSTINCR_3 | DMASRCINCR_0 | DMADSTBYTE | DMAIE);
}
void dma1Start(unsigned char size){
DMA1SZ = (unsigned int)size;
DMA1CTL |= DMAEN;
}
void dma2Init(volatile void * src){
DMA2SZ = 0;
DMACTL1 |= DMA2TSEL__UCA0TXIFG;
__data16_write_addr((unsigned short)&DMA2SA,(unsigned long) src);
__data16_write_addr((unsigned short)&DMA2DA,(unsigned long) &UCA0TXBUF);
DMA2CTL = (DMADT_0 | /*DMALEVEL |*/ DMADSTINCR_0 | DMASRCINCR_3 | DMASRCBYTE /* | DMADSTBYTE | DMAIE*/);
}
void dma2Start(unsigned char size){
DMA2SZ = (unsigned int)size;
DMA2CTL |= DMAEN;
}
Has anyone the same problem? Or maybe I do a mistake in code above? Any idea? I planned to use many fram version of MSP in a huge project but with primary assumption that it will run with DMA correctly. If it is common problem is it possible to workarround it?
Thanks for help,
Andr