-1

I have a some problem with for loop copies' time I don't why for loop is taking much time for the copy small data size. I am using PIC24FJ256GL406 MCU and everything is fine but when operate the UART micro-controller is running slow because some delay is occurring while copy the buffer data. Let me explain you with code and debug log.

Here I am posting the function for the UART transmission. this function is generally transfer only FIRST character and Rest of the byte will be transfer in the Interrupt routine service.

My clock Frequency is 32Mhz So peripheral will be 16 Mhz.

I did not understand why for loop is taking Almost 20 MS for the copy the 16 byte data only. So This time will be increase if data is more.

unsigned int UART1_WriteBuffer(const uint8_t *buffer, const unsigned int bufLen)
{
    //transmit first char

    U1TXREG = buffer[0];

    while (!U1STAbits.TRMT);

    numBytesWritten = bufLen - 1;

    totalByte = 0;

    //get the current time stamp
    WSTimestamp currentTimeStamp = WSGetCurrTimestamp();

    WMLogInfo(GEN_LOG, "current time stamp %ld", currentTimeStamp);

    uint16_t i = 0;

    //memset
    memset(&uart1_txByteQ, 0x00, sizeof(uart1_txByteQ));
    
    for (i = 0; i < numBytesWritten; i++)
    {
        uart1_txByteQ = buffer[i + 1]; //copy the data
    }
    
    _U1TXIE = 1;

    //get last time stamp
    WSTimestamp lastTimeStamp = WSGetCurrTimestamp();

    WMLogInfo(GEN_LOG, "last time stamp %ld ", lastTimeStamp);
     
    ///print the debug
    WMLogInfo(GEN_LOG, "total = %ld MS time taken fo copy the = %d byte", lastTimeStamp - currentTimeStamp, numBytesWritten);

    return bufLen;

}

My Interrupt Routine service.

void __attribute__((interrupt, no_auto_psv)) _U1TXInterrupt(void)
{
    if (totalByte < numBytesWritten)
    {
        U1TXREG = uart1_txByteQ[totalByte++];

        while (!U1STAbits.TRMT);
    }
    else
    {
        _U1TXIE = 0;
        _U1TXIE = 0;
    }

}
 
Console Log.
This is function log. please note.

GEN:main loop current time stamp 6503<\r><\n>
GEN:current time stamp 6506<\r><\n>
GEN:last time stamp 6526 <\r><\n>
GEN:total = 20 MS time taken fo copy the = 16 byte<\r><\n>
GEN:command "AT+QREFUSECS=1,1<\r>" send with len [17]

  • What *is* `uart1_txByteQ`? Is it an array? Then an assignment like `uart1_txByteQ = buffer[i + 1];` doesn't make sense, and shouldn't even build. Please try to create a [mcve] to show us. – Some programmer dude May 10 '21 at 06:44
  • And if you want to copy, why don't you use `memcpy`? – Some programmer dude May 10 '21 at 06:45
  • @Someprogrammerdude Yes uart1_txByteQ Is an array. As you can see the function there only buf[0] character is transmitting and rest of the character will be transfer in Interrupt Routine So uart1_txByteQ Is global Array So i Copy buffer[i+1] to the uart1_txByteQ because 1 Char already Transferred. – Ketan Vadodariya May 10 '21 at 06:48
  • You are waiting in the interrupt for transmitting the byte `while (!U1STAbits.TRMT);` and wasting time. Perhaps and if possible, you should do some `ready-test` before `U1TXREG = xx` – Holger May 10 '21 at 07:08
  • Why don't you: 1-prepare the buffer 2-enable interrupts 3-write first char? At the moment, I would await the first interrupt, you haven't enabled interrupts and the buffer is not prepared? – Holger May 10 '21 at 07:14
  • @Holger Can I Use while (!(U1STAbits.UTXBF == 1)) in interrupt for the transmission. I thing Loading character to the interrupt without check TRMT and UTBF is not working – Ketan Vadodariya May 10 '21 at 08:42
  • 2
    It's a transmit interrupt. When it happens, load the tx register. Do not pass 'Go', do not collect any delays by pointless polling. When there is no more to send in the handler, disable the interrupt. When there is a buffer to send, check if the interrupt is disabled and, if it is, enable it and load the first char into the tx register. – Martin James May 10 '21 at 09:49
  • @MartinJames Thank you for you suggestion. It now fine. I fix the problem. – Ketan Vadodariya May 10 '21 at 09:58
  • @KetanVadodariya then you should either answer your own question, accept and/or upvote the answer given, or delete this question since you say you fixed the problem but didn't explain how. – TomServo May 10 '21 at 20:39

1 Answers1

2

The long delays are caused by busy-waiting for flags in combination with some use-case bug. Why are you using Tx interrupt in the first place in case you intend to busy-wait poll for a flag anyhow? The ISR doesn't make sense - it would seem that you should simply drop Tx interrupts entirely.

In addition, you have a naive implementation of buffer copies. It's a very common embedded systems beginner bug to hard copy RAM buffers needlessly. There's very few cases where you actually need to do hard copies and this isn't one. Instead you should use a system with double buffers and simply swap a pointer between them:

static uint8_t buf1 [n];
static uint8_t buf2 [n];
static uint8_t* rx_buf = buf1;   // buffer used by rx ISR
static uint8_t* app_buf = buf2;  // buffer used by the application

...

if(rx_done)
{ // swap buffers
  uint8_t* tmp = rx_buf;
  rx_buf = app_buf;
  app_buf = tmp;
}

This also solves the double-buffering problem where an UART rx interrupt needs to store it's incoming data somewhere at the same time as the main program uses data. You'll need to protect against race conditions somehow - with a semaphore etc. And you'll need to declare variables shared with ISRs volatile to protect against bad compiler optimizers.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Here There is not problem with buffer. Here problem Is I have an 1024 Byte data which I have to transfer to the UART Interrupt So I wrote the function Who Transfer the first character Only And rest of it it would be transfer via Interrupt service. Because of while on in Transfer function so it was holding process. To Avoid I did this. – Ketan Vadodariya May 10 '21 at 08:54