UART write buffer with PDC

I am having problem writing to USARt using const char buffer and char arrray.

Here is my UART write function:

unsigned int USART_Send(  unsigned char *p_pucData, 
                              unsigned int p_unLen)
{


  AT91C_BASE_US2->US_TPR = (unsigned int)p_pucData;
  AT91C_BASE_US2->US_TCR =  p_unLen;
  AT91C_BASE_US2->US_PTCR = AT91C_PDC_TXTEN;


  while((AT91C_BASE_US2->US_CSR & ((0x1 << 11) | (0x1 << 4) ) ) == 0);

   AT91C_BASE_US2->US_PTCR = AT91C_PDC_TXTDIS;

    return p_unLen;    
}

      

Below is a function working on a const char * value:

USART_Send("IsitDone?",9);   //Working

      

If I use an array buffer like below it shows garbage characters, wonder why?

 unsigned char arr[10];
  memcpy(arr, "HelloWorld", 10);
  USART_Send(arr, sizeof(arr));  //Not working properly displaying Garbage chars

      

+3


source to share


1 answer


Ricardo Crado is loyal. You are facing the following problem:
arr is created on the stack
arr is filled
call USART_Send
    fill transmit pointer, counter, enable tx requests
    /* peripheral state is TXBUFE = '0' and ENDTX = '0' because:           */
    /* TXBUFE = '0' when PERIPH_TCR != 0 and                               */
    /* ENDTX = '0' when PERIPH_TCR != 0                                    */
    /* but we just wrote to PERIPH_TCR, so it != 0                       */
    /* both conditions are satisfied, b/c the transfer hasn't started yet! */
    wait until (TXBUFE = '0' and ENDTX = '0')
    /* your code thinks PDC is done here      */
    /* but in reality, PDC is getting started */
    disable tx requests
return from sub-function
overwrite stack (and arr) with unrelated data here
/* PDC might push out last word(s) here due to pipelining/        */
/* instruction cache/side effects/you-name-it                     */
/* even though its matrix requests were disabled a few cycles ago */

      

Solutions:

  • copy to global clipboard or
  • Wait a few cycles between enabling tx requests and checking if the PDC is running (possibly integer baud), or
  • read PERIPH_TCR and check if it is zero instead of checking flags


Ideally, you allocate some heap memory for strings and deallocate it after the PDC is done asynchronously with your actual code. You might want to check if some kind of interrupt happened after the PDC / peripheral completes and then free the memory it is reading from.

If you don't have dynamic memory allocation then use a global buffer buffer and render the string / char send function to use that buffer.

0


source







All Articles