This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP-EXP430FR5994: uart receive dma value wrap around

Part Number: MSP-EXP430FR5994


I have the BQ uart setup to receive with DMA trigger. 

I have dma_value set as uint16_t because measurement data size is uint16_t. However Initialization data is uint8_t. 

BQInitTest shows the correct sequence of initialization bytes.

But what I am seeing in dma_value is shown in picture dmaValue. I don't understand the byte ordering in dmaValue. BQ response to initalization is correct, as seen in the logic analyzer. I have attached the code for DMA setup and DMA ISR, uartSend. uartReceive is also attached, however the problem occurs before this.

extern uint16_t bq79600Addr;

extern BYTE autoaddr_response_frame[(1+6)*TOTALBOARDS];
extern uint16_t response_frame[(8)*TOTALBOARDS];

uint8_t uartRxLen;
uint16_t dma_value[(8)*TOTALBOARDS] = {0};
uint8_t startMeasure = 0;
uint8_t bqAddr = 0;

void DMA_Init(){
    __data20_write_long((uintptr_t)&BQUART_DMASA, (uintptr_t)&BQUART_RXBUF);
    __data20_write_long((uintptr_t)&BQUART_DMADA, (uintptr_t) dma_value);

    BQUART_DMACTL &= ~DMAEN;
    DMACTL0 |= BQUART_DMA_RX_TRIGGER;
    DMACTL4 |= DMARMWDIS;

    //Repeated single transfer; increment destination address; source address unchanged;
    //byte to byte transfer source to DMA; byte to byte transfer destination to DMA;
    //rising edge DMA trigger; DMA enable

    BQUART_DMACTL |= DMADT_4|DMADSTINCR_3|DMASRCINCR_0|DMASRCBYTE__BYTE|DMADSTBYTE__BYTE|DMA_TRIGGER_RISINGEDGE|DMAEN;

}


int ReadFrameReq(BYTE bID, uint16_t wAddr, BYTE bByteToReturn, BYTE bWriteType, BYTE rxLen) {
    bReturn = bByteToReturn - 1;

    uartRxLen = rxLen;

    //PN setting a flag to identify when BQ79600 address is being read
    if (wAddr == 0x2001)
        bqAddr = 1;
    if (wAddr != 0x2001)
        bqAddr = 0;

    if (bReturn > 127)
        return 0;

    return WriteFrame(bID, wAddr, &bReturn, 1, bWriteType);
}

void uartSend(int length, uint8_t * data){
    uint8_t i;

    BQUART_DMASZ = uartRxLen;
    BQUART_DMACTL |= DMAEN;
    BQUART_DMACTL |= DMAIE;


    for (i = 0; i < length; i++){
        while (!(BQUART_IFG & UCTXIFG));
        BQUART_TXBUF = data[i];
    }


}

void uartReceive(void){
uint8_t i;
uint8_t aaResp[7*TOTALBOARDS];

    if (startMeasure == 1){
        memcpy(response_frame, dma_value, uartRxLen);
    }

    if (bqAddr == 1){
        for (i = 0; i < 4; i++){
           aaResp[2*i] = (uint8_t) dma_value[i] & 0x00ff;
           aaResp[2*i+1] = (uint8_t) ((dma_value[i] & 0xff00) >> 8);

        }

        memcpy(autoaddr_response_frame, aaResp, uartRxLen+1);
        bq79600Addr = autoaddr_response_frame[4];
        startMeasure = 1;
    }


}

#pragma vector=DMA_VECTOR
__interrupt void dmaIsrHandler(void)
{
    switch(__even_in_range(DMAIV,  BQUART_DMAIV_IFG))
    {
    case BQUART_DMAIV_IFG:
        BQUART_DMACTL &= ~DMAIE;

        uartReceive();

        // Exit low power mode on wake-up
        __bic_SR_register_on_exit(LPM4_bits);
        break;
    case DMAIV_DMA0IFG:
        break;

    case DMAIV_DMA2IFG:
        break;

    case DMAIV_DMA3IFG:
            break;

    case DMAIV_DMA4IFG:
        break;

    case DMAIV_DMA5IFG:
        break;

    default: break;
    }
}

  • It isn't clear from the discussion exactly what your complaint is. But I see you telling the DMA controller to read a byte from the source and write a byte to the destination. The destination happens to be an array of ints. If you were expecting the DMA controller to know that it was an integer array and to increment its address accordingly, you are badly mistaken.

    The DMA controller can read a byte and write to a word, clearing the upper half of the word if you desire. Perhaps that is what you were expecting. If so, then you need to tell the DMA controller.

  • extern uint16_t bq79600Addr;
    
    extern BYTE autoaddr_response_frame[(1+6)*TOTALBOARDS];
    extern uint16_t response_frame[(8)*TOTALBOARDS];
    
    uint8_t uartRxLen;
    uint16_t dma_value[(8)*TOTALBOARDS] = {0};
    uint8_t startMeasure = 0;
    uint8_t bqAddr = 0;
    
    void DMA_Init(){
        __data20_write_long((uintptr_t)&BQUART_DMASA, (uintptr_t)&BQUART_RXBUF);
        __data20_write_long((uintptr_t)&BQUART_DMADA, (uintptr_t) dma_value);
    
        BQUART_DMACTL &= ~DMAEN;
        DMACTL0 |= BQUART_DMA_RX_TRIGGER;
        DMACTL4 |= DMARMWDIS;
    
        //Repeated single transfer; increment destination address; source address unchanged;
        //byte to byte transfer source to DMA; byte to byte transfer destination to DMA;
        //rising edge DMA trigger; DMA enable
    
        BQUART_DMACTL |= DMADT_4|DMADSTINCR_3|DMASRCINCR_0|DMASRCBYTE__WORD|DMADSTBYTE__WORD|DMA_TRIGGER_RISINGEDGE|DMAEN;
    
    }
    
    void uartSend(int length, uint8_t * data){
        uint8_t i;
    
        BQUART_DMASZ = uartRxLen;
        BQUART_DMACTL |= DMAEN;
        BQUART_DMACTL |= DMAIE;
    
    
        for (i = 0; i < length; i++){
            while (!(BQUART_IFG & UCTXIFG));
            BQUART_TXBUF = data[i];
        }
    
    
    }
    
    void uartReceive(void){
    uint8_t i;
    
        if (startMeasure == 1){
            memcpy(response_frame, dma_value, uartRxLen);
        }
    
        if (bqAddr == 1){
            for (i = 0; i < uartRxLen; i++){
                autoaddr_response_frame[i] = (uint8_t) dma_value[i];
            }
            bq79600Addr = autoaddr_response_frame[4];
            startMeasure = 1;
        }
    
    
    }
    
    #pragma vector=DMA_VECTOR
    __interrupt void dmaIsrHandler(void)
    {
        switch(__even_in_range(DMAIV,  BQUART_DMAIV_IFG))
        {
        case BQUART_DMAIV_IFG:
            BQUART_DMACTL &= ~DMAIE;
    
            uartReceive();
    
            // Exit low power mode on wake-up
            __bic_SR_register_on_exit(LPM4_bits);
            break;
        case DMAIV_DMA0IFG:
            break;
    
        case DMAIV_DMA2IFG:
            break;
    
        case DMAIV_DMA3IFG:
                break;
    
        case DMAIV_DMA4IFG:
            break;
    
        case DMAIV_DMA5IFG:
            break;
    
        default: break;
        }
    }

    Transfering word to byte helps some. However, I don't understand the order of bytes that are in dma_value.

    In dma_value, I expect to see bytes that are in index 1-6 in indices 0-5. The byte in index 0 should be in index 6 because it is part of the CRC.

    When dma_value is copied to autoaddr_response_frame, byte 0 is not being copied correclty. For some reason 0x55 is becoming 0x9C. Rest of the copy is OK.

  • Since  you don't clear RXIFG before enabling DMA, it is really easy for a byte to be hanging out in RXBUF. So when you enable DMA, you get an immediate trigger. This would put the last byte of the previous frame into the first byte of the current frame.

**Attention** This is a public forum