RS485 receive interrupt using SCB UART mode

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
amjoc_4089431
Level 2
Level 2
First like received


Hello All,

I am working on PSOC4 CY8C4246AZI-445 Controller and implementing RS485 communication using SCB UART mode.

I am trying to receive data from RS485 slave, I configured Uart in receive interrupt and I am using RX FIFO not empty interrupt.

Problem is,if i start the device control starts hitting ISR  and even if there is no input data to receive still interrupt is generating continuously and it's filling receive buffer with NULL which is not expected and due to this continuous interrupt, I am not able to receive data in required sequence.


I tried a lot of things but still facing same issue, ISR is getting executed continuously.

Please help me on this.

Thanks in advance.

Amit.

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amit-san,

I saw the log, it seems that even after you removed the slave,

the master is receiving one byte in each loop.

I tried the program with CY8CKIT-044 and connected rx485_rx and rx485_tx to fool the program,

and it was correctly reading 7 bytes data (as it is discarding one byte).

So currently I assume that your RS485 I/F is actually feeding 1 byte data when no data is being sent from the slave.

And we could study about this for more time, but as far as we know that the length is not 45 bytes + 1 bytes,

the data is guaranteed to be bad, so why don't we just discard and ignore the incomplete data?

I added some modification to the program

(1) print_data()

Although in the previous version, print_data() knew that the first byte of the data buffer is invalid and the real length of the data is -1 to the given length, I think that is very kludge way of taking care of the situation.

So I returned the behavior of this function to print given number of data.

======================

void print_data(char *title, uint8_t data[], int num_data)

{

    char tmp_str[10] ;

    int i ;

    if (title && *title) {

        print(title) ;

        sprintf(tmp_str, "[%d] ", num_data) ;

        print(tmp_str) ;

        for (i = 0 ; i < num_data ; i++ ) { /* discarding the first data 26-Jun-2019 */

            sprintf(tmp_str, "%02X ", data) ;

            print(tmp_str) ;

        }

        print("\r\n") ;

        while(UART_GetTxBufferSize() > 0) {

            ; /* wait tx buffer to be empty */

        }

    }

}

======================

(2) main()

As I wrote above any received data whose length is not expected(45) bytes + 1 byte (0x00), it is a garbage data.

So let's not deal with them and just discard them!.

For this we could use the if condition as

  if (str_1_index == 46) {

But this time I only used

  if (str_1_index > 1) {

So that we can monitor bad data whose length is not 0.

Meantime, as I modified the print_data(), I provide the address of the second byte of str_1_buf[],

which is &str_1_buf[1], so that print_data() can handle it as a normal array.

And the length is also decreased by 1 to match with it, so I provided "str_1_index-1".

=====================

int main(void)

{

    uint8 command[10] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x14, 0xF0, 0x04 } ; /* reg read */

    int cmd_len = 8 ;

  

    init_hardware() ;

    UART_PutString("\r\nUART Init Done\r\n");

  

    for(;;)

    {

        UART_PutString("\n\rInfinite loop");      

        reset_buffers() ;

    

        send_command(command, cmd_len) ;

      

        str_1_index = recv_response(str_1_buf) ;

      

        if (str_1_index > 1) { /* we could make this (str_1_index > 45) */                          

            print_data("\r\nBuff", &str_1_buf[1], str_1_index-1) ;

        } else {

            UART_PutString(" No Data Received\r\n") ;

        }

      

        CyDelay(1000) ;

    }

}

=====================

I hope that this can settle this topic (at least for the time being.)

Best Regards,

28-Jun-2019

Motoo Tanaka

View solution in original post

14 Replies
lock attach
Attachments are accessible only for community members.
amjoc_4089431
Level 2
Level 2
First like received

Please find attached serial log and my project folder.

Thanks.

Amit

0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amit-san,

Your code looks familiar to me 😉

But I noticed there are some lines I'd like to modify.

(1) Please don't place UART_2_PutString() in an ISR (MyRx1Int)

So I modified it as below.

isr_1_ClearPending() may not be necessary, but to be in the safer side I added.

===================

CY_ISR(MyRx1Int)

{

    uint8_t int_flag ;

    isr_1_ClearPending() ; /* moto (May be not necessary) */

    UART_1_ClearRxInterruptSource(UART_1_INTR_RX_NOT_EMPTY) ; /* for PSoC 4 */

    if (UART_1_SpiUartGetRxBufferSize())

    {

        int_flag = CyEnterCriticalSection() ;

        rx_1_buf[rx_1_write_index] = UART_1_UartGetByte() ;

        rx_1_write_index = (rx_1_write_index + 1) % BUF_1_LENGTH ;

        CyExitCriticalSection(int_flag) ;

    }

//    UART_2_PutString("\r\nISR\r\n"); // we don't want to have this in an ISR /* moto */

}

===================

(2) We may want to enable global interrupt after set up is completed.

So I modified it as below

===============================

//    CyGlobalIntEnable; /* Enable global interrupts. */ /* moto */

    CyDelay(5000);// Initialization delay

    UART_1_SpiUartClearRxBuffer() ;

    isr_1_ClearPending() ; /* moto (May be not necessary) */

    UART_1_ClearRxInterruptSource(UART_1_INTR_RX_NOT_EMPTY) ; /* for PSoC 4 */ /* moto */

    isr_1_StartEx(MyRx1Int); 

   UART_1_Start();

    UART_2_Start();  

    CyGlobalIntEnable; /* Enable global interrupts. */ /* moto */  

    UART_2_PutString("\r\nUART Init Done\r\n");

===============================

(3) If you reset rx_1_write_index and rx_1_read_index,

we'd like to clear the buffers, too.

=======================

    isr_1_Disable() ;                      /* moto */

    UART_1_SpiUartClearRxBuffer() ;        /* moto */

    UART_1_SpiUartClearTxBuffer() ;        /* moto */

    UART_1_ClearRxInterruptSource(UART_1_INTR_RX_NOT_EMPTY) ; /* for PSoC 4 */ /* moto */

    rx_1_write_index = rx_1_read_index = 0;

    isr_1_Enable() ;                       /* moto */

=======================

(4) Writing the size for each byte may be too much and also using PutChar() may cause the terminal behave strange.

So I modified the part as below

===========================

        if (rx_1_read_index != rx_1_write_index) {     /* moto */

            UART_2_PutString("\n\rRx byte = ");        /* moto */

            sprintf(tmp_str, "0x%02X\n\r", rx_1_buf[rx_1_read_index]) ; /* moto */

            UART_2_PutString(tmp_str);                   /* moto */

        }

        while(rx_1_read_index != rx_1_write_index)

        {

//            UART_2_PutString("\n\rRx byte = ");                  /* moto */

//            UART_2_PutChar(rx_1_buf[rx_1_read_index]);           /* moto */

===========================

By the way, here if the first byte of the received data is the length,

it can be non printable character,

that case you may not want to add that character in the str_1_buf[].

If it's the case un-comment following line ;

==============

//          rx_1_read_index = (rx_1_read_index + 1) % BUF_1_LENGTH ; /* moto, if you don't want to add this to str_1_buf[] */

==============

(5) Your program output the result only when str_1_index >= STR_1_LENGTH

    is this what you are expecting?

   If there is/are delimiter(s) in the received data, we could write

=========================

if ((is_delimiter(rx_1_buf[rx_1_read_index])) {

   str_1_buf[str_1_index] = 0 ;

   UART_2_PutString("\n\rBuff = ") ;

   UART_2_PutString(str_1_buf) ;

   str_1_index = 0 ;

} else {

   str_1_buf[str_1_index++] = rx_1_buf[rx_1_read_index] ;

}

=========================

Or, you may want to put char each receiving char.

Then replace the block starting from while(rx_1_read_index != rx_1_write_index) to

=========================

while (rx_1_read_index != rx_1_write_index) {

      UART_PutChar(rx_1_buf[rx_1_read_index]) ;

      rx_1_read_index = (rx_1_read_index + 1) % BUF_1_LENGTH ;

}

=========================

After all, I wonder if these can fix your problem though.

Best Regards,

16-Jun-2019

Motoo Tanaka

0 Likes
lock attach
Attachments are accessible only for community members.

Hello Moto,

Thanks For Reply.

Actually, I am using your code, I got it from this forum only.

I made changes as per your suggestions, it's working but still, sometimes

that issue is occurring.

I don't understand why ISR is hitting even if there is no data to receive

on UART.

In this project, i am going to receive data from multiple slaves,in

response frame, there is no delimiter,

there is NO OF BYTES field and I am using this field to receive all

bytes(now its 45 bytes).

Could you please look into the attached project(with your changes) and

serial log.

https://drive.google.com/drive/folders/1RC2emcv2xaslOlQGBPu-f7TQFanrmsVe

Thanks,

Amit.

On Sun, Jun 16, 2019 at 2:34 PM Motoo Tanaka <community-manager@cypress.com>

0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amit-san,

It seems that you are sending and receiving binary data instead of readable letters.

If it's the case may be using UART_PutArray() to display data for debugging to a serial terminal is not a good idea.

It often causes the terminal program wrong or strange display.

Instead how about using something like

================

void print_data(uint8_t data[], int num_data)

{

    int i ;

    char tmp_str[4] ;

    for (i = 0 ; i < num_data ; i++ ) {

      sprintf(tmp_str, "%02X ", data & 0xFF) ;

      UART_PutString(tmp_str) ;

    }

    UART_PutString("\r\n") ;

}

================

Attached is a version with above modification.

Best Regards,

21-Jun-2019

Motoo Tanaka

0 Likes
lock attach
Attachments are accessible only for community members.

Hello Motoo,

I have tested your code,but I am not able to read exact response bytes.

Every time it reads different no bytes,you can check it from serial log, also I have attached image of query and required response from slave.

Please help me on this.

Amit

0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amit-san,

Your log and the query_and_response information is very helpful!

I've entered the first 20 logs into Excel and tried to organize them.

log_image.JPG

Surprisingly NO record was received correctly, but there are some points I noticed.

(1) There were no response for the first 4 queries

(2) Almost all transactions failed to receive the first part of the response

For (1), We may need to send some wake up request to the device and wait some time for the device to be ready.

For (2), as I wanted to clearly send the query, I let the send command to wait for the tx buffer to be empty,

but probably it was not necessary,  so I commented out the while() in the send_command()

===================

void send_command(uint8_t command[], int cmd_len)

{

    rs485_SpiUartClearTxBuffer();

    Pin_1_Write(1);// RE/DE Pin High (Tx Mode)

    CyDelay(10);          

    rs485_SpiUartPutArray(command,cmd_len);// Send data on RS485

//    while(rs485_SpiUartGetTxBufferSize() > 0) { } // wait tx buffer // removed on 15-Jun-2019 <---

    CyDelay(10);

    Pin_1_Write(0);        // RE/DE Pin Low (Put in Rx Mode)  

}

====================

So would you test attached project and let me know the result?

Best Regards,

25-Jun-2019

Motoo Tanaka

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

BTW, as you had CyDelay(10) in the original program, I left it, but 10ms is rather a long time,

May be you want to try the following combination

(1) comment out both

===============

    Pin_1_Write(1);// RE/DE Pin High (Tx Mode)

    CyDelay(10);          

    rs485_SpiUartPutArray(command,cmd_len);// Send data on RS485

//    while(rs485_SpiUartGetTxBufferSize() > 0) { } // wait tx buffer // removed on 15-Jun-2019

//    CyDelay(10);

    Pin_1_Write(0);        // RE/DE Pin Low (Put in Rx Mode)

===============

(2) comment out only CyDelay(10)

===============

    Pin_1_Write(1);// RE/DE Pin High (Tx Mode)

    CyDelay(10);          

    rs485_SpiUartPutArray(command,cmd_len);// Send data on RS485

    while(rs485_SpiUartGetTxBufferSize() > 0) { } // wait tx buffer // removed on 15-Jun-2019

//    CyDelay(10);

    Pin_1_Write(0);        // RE/DE Pin Low (Put in Rx Mode)

===============

(3) comment out only while()

===============

    Pin_1_Write(1);// RE/DE Pin High (Tx Mode)

    CyDelay(10);          

    rs485_SpiUartPutArray(command,cmd_len);// Send data on RS485

//    while(rs485_SpiUartGetTxBufferSize() > 0) { } // wait tx buffer // removed on 15-Jun-2019

    CyDelay(10);

    Pin_1_Write(0);        // RE/DE Pin Low (Put in Rx Mode)

===============

moto

0 Likes
lock attach
Attachments are accessible only for community members.

Hello Motoo,

I saw your excelsheet, I want to tell you that slave device takes some time

to get ready that is why for first 4 commands I am not receiving response

from slave.

I tried all 3 combinations that you suggested

1.Commented while()

2.Commented CyDelay(10)

3.Both commented.

I have attached respective log files please take a look.

Thanks a lot.

Amit.

On Tue, Jun 25, 2019, 6:22 AM Motoo Tanaka <community-manager@cypress.com>

0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amit-san,

Thank you very much for your testing!

Now we are sure that using only commenting "while" gave us the most better result!

(since it's still wrong, we can not say the best, can we?)

I entered the value and what I noticed was

(1) 1 byte shifts each line

(2) except the line 10, and if we ignore "00" before "01 04 28 1E", data read seems to be OK.

log2_image.JPG

About (1), I wonder if there is always "00" before the expected response "01 4 28 1E" or "00" comes as the 46th char.

To test, I added buffer reset (reset read/write index in the buffer to discard data from the previous line.

Best Regards,

25-Jun-2019

Motoo Tanaka

P.S. I commented CyDelay(10) for 190625B by mistake, use 190625C which is the "while" commented.

0 Likes
lock attach
Attachments are accessible only for community members.

Dear Motoo,

After using resetbuffer function, now i am able to receive 45 bytes continuously,

But issue is, I am getting "00" as first byte which is wrong byte.

Please take a look in to attached log file.

Thanks,

Amit

0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amit-san,

It seems that you are almost there.

Although I was expecting that the "00" was the last char in the response as the device may add NULL at the end of it's response, it was not the case.

Meantime, I noticed that even when the device is not responding, the program has been receiving 1 byte, which is "00".

The first 4 responses are all 1 byte long "00"

===========

UART Init Done

Infinite loop

Buff[1] 00

Infinite loop

Buff[1] 00

Infinite loop

Buff[1] 00

Infinite loop

Buff[1] 00

===========

Then all the remaining transactions are getting "00" as the first letter.

I ported the program to CY8CKIT-044 and ran, as the board is not connected to the device, the length of Buff was always 0.

So the program does not report length 1 unless it receives it.

I wonder if the device connected via RS485 outputs "00" when Pin_1_Write(0) is executed

or device received a command.

Attached is a version, which reads up to "STR_1_LENGTH + 1" bytes then discard the first byte.

Best Regards,

26-Jun-2019

Motoo Tanaka

0 Likes
lock attach
Attachments are accessible only for community members.

Dear Motoo,

Thanks a lot..

Finally I am receiving exact response from slave device.

I agreed with your thoughts, related to 00(first byte),I also observed that, without connecting slave device,our master device is receiving 00 (NULL) byte and i also observed this ,when I comment Pin_1_write(0);(which puts rs485 in receive mode) there is no such NULL data.

Previously i observed one thing like even if there is no slave device connected,still device generating continuous RX interrupt,but whenever I comment Pin_1_write(0); then receive interrupt stopped generating.

Now it's working fine, I am getting exact response but when I disconnect the slave,still I am receiving data due to which buffer index gets incremented to 1,it should be 0 if there is no data to receive.

I have attached log file,you can check due to some data buff[ 1 ] printing at the end of log at that time I disconnected slave device.

Thanks.

Amit.

0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Amit-san,

I saw the log, it seems that even after you removed the slave,

the master is receiving one byte in each loop.

I tried the program with CY8CKIT-044 and connected rx485_rx and rx485_tx to fool the program,

and it was correctly reading 7 bytes data (as it is discarding one byte).

So currently I assume that your RS485 I/F is actually feeding 1 byte data when no data is being sent from the slave.

And we could study about this for more time, but as far as we know that the length is not 45 bytes + 1 bytes,

the data is guaranteed to be bad, so why don't we just discard and ignore the incomplete data?

I added some modification to the program

(1) print_data()

Although in the previous version, print_data() knew that the first byte of the data buffer is invalid and the real length of the data is -1 to the given length, I think that is very kludge way of taking care of the situation.

So I returned the behavior of this function to print given number of data.

======================

void print_data(char *title, uint8_t data[], int num_data)

{

    char tmp_str[10] ;

    int i ;

    if (title && *title) {

        print(title) ;

        sprintf(tmp_str, "[%d] ", num_data) ;

        print(tmp_str) ;

        for (i = 0 ; i < num_data ; i++ ) { /* discarding the first data 26-Jun-2019 */

            sprintf(tmp_str, "%02X ", data) ;

            print(tmp_str) ;

        }

        print("\r\n") ;

        while(UART_GetTxBufferSize() > 0) {

            ; /* wait tx buffer to be empty */

        }

    }

}

======================

(2) main()

As I wrote above any received data whose length is not expected(45) bytes + 1 byte (0x00), it is a garbage data.

So let's not deal with them and just discard them!.

For this we could use the if condition as

  if (str_1_index == 46) {

But this time I only used

  if (str_1_index > 1) {

So that we can monitor bad data whose length is not 0.

Meantime, as I modified the print_data(), I provide the address of the second byte of str_1_buf[],

which is &str_1_buf[1], so that print_data() can handle it as a normal array.

And the length is also decreased by 1 to match with it, so I provided "str_1_index-1".

=====================

int main(void)

{

    uint8 command[10] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x14, 0xF0, 0x04 } ; /* reg read */

    int cmd_len = 8 ;

  

    init_hardware() ;

    UART_PutString("\r\nUART Init Done\r\n");

  

    for(;;)

    {

        UART_PutString("\n\rInfinite loop");      

        reset_buffers() ;

    

        send_command(command, cmd_len) ;

      

        str_1_index = recv_response(str_1_buf) ;

      

        if (str_1_index > 1) { /* we could make this (str_1_index > 45) */                          

            print_data("\r\nBuff", &str_1_buf[1], str_1_index-1) ;

        } else {

            UART_PutString(" No Data Received\r\n") ;

        }

      

        CyDelay(1000) ;

    }

}

=====================

I hope that this can settle this topic (at least for the time being.)

Best Regards,

28-Jun-2019

Motoo Tanaka

Dear Motoo,

Thanks a lot.

Finally issue resolved.

I really appreciate your continuous support and help.

Thank you very much   

Amit.