3

I'm having a problem with writing to a 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 function working with const char* like:

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

If I use a array buffer like below it is showing garbage characters, wonder why ?

 unsigned char arr[10];
  memcpy(arr, "HelloWorld", 10);
  USART_Send(arr, sizeof(arr));  //Not working properly displaying Garbage chars
Ashok
  • 601
  • 1
  • 17
  • 32
  • Which processor, which UART, which baud rate? etc etc – Prof. Falken Sep 05 '14 at 07:46
  • Btw, `0x01` is very much harder to read than `1`. – unwind Sep 05 '14 at 07:49
  • its on ATMEL AT91SAM9M10 controller, UART2 and baudrate is 115200 – Ashok Sep 05 '14 at 08:44
  • Looks like memory cache issue. Insert cache write back instruction after memcpy. – alexander Sep 05 '14 at 10:59
  • @alexander any sample code for cache write back instruction ? – Ashok Sep 05 '14 at 11:57
  • Asht, what sdk (runtime) do you use? Anyway, try to find string 'cache' inside sdk headers, docs to find examples. I'm not expert in AT91SAM9M10, I faced similar problem on another CPU. – alexander Sep 05 '14 at 12:21
  • Asht, another solution is to allocate physically continuous `arr` buffer into non cacheable memory, not on stack. This solution is sdk specific. For example, you could place `arr` into appropriate memory segment using linker option or call specific memory allocation function (like dma_alloc_coherent for linux kernel). – alexander Sep 05 '14 at 12:44
  • 1) Rather than say "it is showing garbage characters", post what was shown. 2) Do you have a sequence issue? Was `USART_Send(arr, sizeof(arr));` done shortly after `USART_Send("IsitDone?",9);`? If so, reverse order. – chux - Reinstate Monica Sep 05 '14 at 14:21
  • Check your baud rate and parity setting are correct to work with what you're interfacing to. – DiBosco Sep 08 '14 at 14:19
  • arr is local variable? just try define it as static var. – Ricardo Crudo Oct 06 '14 at 19:39
  • 1
    What I think that can be happening is that you're calling the UART_Send passing a local variable thus any moment, before the data be send (this can take some time depending on baud rate), this memory could be used in other context. – Ricardo Crudo Oct 06 '14 at 19:44

1 Answers1

0

Ricardo Crudo is correct. You run into 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's != 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 a global buffer or
  • wait some cycles between enabling tx requests and checking if the PDC is done (possibly a whole baud tick) or
  • read back PERIPH_TCR and check if it's zero instead of checking the flags

Ideally, you would allocate some dynamic memory for strings and deallocate it after the PDC is done asynchronously to your actual code. You might want to check if you can get some kind of interrupt after the PDC/peripheral is done, then deallocate the memory it read from.

If you don't have dynamic memory allocation, then use the a global ring buffer and abstract your string/char send function to use this buffer instead.

FRob
  • 3,883
  • 2
  • 27
  • 40