• AVR Freaks

Helpful ReplyHot!Checksum in UART from PIC18F27K42

Author
fabianpi
Starting Member
  • Total Posts : 63
  • Reward points : 0
  • Joined: 2017/03/26 15:30:13
  • Location: 0
  • Status: offline
2020/03/30 15:25:41 (permalink)
0

Checksum in UART from PIC18F27K42

I'm learning a bit more about UART communications in (2) PIC18F27K42 and I was trying to write the code for the checksum method using the MCC Configutaror tool, however, I have not being able to make it work properly. 

I may have problems because of my interpretation of the datasheets documentation. 

From datasheet in page 493: 
31.13.1 TRANSMIT CHECKSUM METHOD
1. Clear the UxTXCHK register.
2. Set the C0EN bit.
3. Send all bytes of the transaction output.
4. Invert UxTXCHK and send the result as the last byte of the transaction.
 
31.13.2 RECEIVE CHECKSUM METHOD
1. Clear the UxRXCHK register.
2. Set the C0EN bit.
3. Receive all bytes in the transaction including the checksum byte.
4. Set MSb of UxRXCHK if 7-bit mode is selected.
5. Add 1 to UxRXCHK.
6. If the result is ‘0’, the checksum passes, otherwise it fails.
 
for the checksum I enabled the C0EN bit initially and everytime I made a communication with the other MCU. I will paste the process I made for writing and reading. 
Writing: 
void UART1_Write(uint8_t txData)
{
    while(0 == PIR3bits.U1TXIF)
    {
    }
    
    
    // code originally ends here by MCC configurator
    U1TXB = txData; // Write the data byte to the USART.
    
    // I added myself this pieces of code
    // 1. clear the UxTXCHK register
    U1TXCHK = 0;
    // 2. Set C0EN bit
    U1CON2bits.C0EN = 1;
    // 3. Send all bytes of the transaction output
    U1TXCHK = U1TXB;
    // 4. INVERT U1TXCHK and send the result as the last byte of the
    // transaction
    U1TXCHK = ~U1TXCHK;
    
    U1TXB = U1TXCHK;
}

// I called this function in the infinite loop to send data to the other MCU
void send_tx(void) {
    uint8_t tx_data = 20;
    UART1_Write(tx_data);
    __delay_ms(2000);
}

 
For reading: 
uint8_t UART1_Read(void)
{
    while(!PIR3bits.U1RXIF)
    {
    }

    uart1RxLastError.status = 0;

    if(U1ERRIRbits.FERIF){
        uart1RxLastError.ferr = 1;
        UART1_FramingErrorHandler();
    }

    if(U1ERRIRbits.RXFOIF){
        uart1RxLastError.oerr = 1;
        UART1_OverrunErrorHandler();
    }

    if(uart1RxLastError.status){
        UART1_ErrorHandler();
    }
    // code originally ends here by MCC configurator
    // return U1RXB;
    
    // 1. clear the U1RXCHK register
    U1RXCHK = 0;
    // 2. Set C0EN bit
    U1CON2bits.C0EN = 1;
    // Receive all bytes in the transaction
    U1RXCHK = U1RXB;
    
    // Add 1 to U1RXCHK
    U1RXCHK += 1;
    
    return (U1RXCHK == 0) ? U1RXB : 0;
    
}

// I called this function to test the received bytes
void receive_rx(void) {
    printf("%d\n", getch());
    __delay_ms(1000);
}

 
So I was looking for a help from the community, what am I missing ? Am I missunderstanding the concept from the UART? 

All I get from the serial monitor (using an arduino skecth) is printed 0s 
which is because the UART1_Read() function is returning 0 when the data is not successfully received. 
 
I tested the normal UART communication between both devices and are working correctly, but when I add the checksum algorithm is when the problem appears. 

I would like to know what do you think I could do! Thanks
#1
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/30 15:31:42 (permalink)
+1 (1)
fabianpi
...
So I was looking for a help from the community, what am I missing ? Am I missunderstanding the concept from the UART?

Yes, you are totally misunderstanding the process.
 
Do this bit once, BEFORE you send all your data

1. Clear the UxTXCHK register.
2. Set the C0EN bit.

Then, as instructed, send your data. All of it, not just one byte.

3. Send all bytes of the transaction output.

then after all the data has been sent, do the last step

4. Invert UxTXCHK and send the result as the last byte of the transaction.

 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#2
fabianpi
Starting Member
  • Total Posts : 63
  • Reward points : 0
  • Joined: 2017/03/26 15:30:13
  • Location: 0
  • Status: offline
Re: Checksum in UART from PIC18F27K42 2020/03/30 17:28:00 (permalink)
0
Hi and thanks for your reply! 

Well I modified the code and leave the way it was the UART configured by the MCC and modify my current send_tx() and receive_rx() functions. 
sender code: 
void send_tx(void) {
    // 1. clear the UxTXCHK register
    U1TXCHK = 0;
    // 2. Set C0EN bit
    U1CON2bits.C0EN = 1;
    
    // 3. send all bytes of the transaction output
    uint8_t tx = 25; // testing sending 25 
                    // to read it in the other MCU
    UART1_Write(tx);
    
    // 4. Invert UxTXCHK and send the result
    // as the last byte of the transaction.
    U1TXCHK = ~U1TXCHK;
    UART1_Write(U1TXCHK);
    
    __delay_ms(2000);
}

 
receiver code: 
void receive_rx(void) {
    
    // 1. clear the U1RXCHK register
    U1RXCHK = 0;
    // 2. Set C0EN bit
    U1CON2bits.C0EN = 1;
    // 3. receive all bytes in the transaction
    uint8_t d = UART1_Read();
    
    // 4. add 1 to U1RXCHK
    U1RXCHK = U1RXCHK + 1;
    
    printf("%d\r\n", d);
    (U1RXCHK == 0) ? printf("%d\r\n", d) : printf("no data available\r\n");
}

 
 
and the output in the serial monitor is the following in each loop:
25
no data available
230
no data available
 
Sorry if I am not getting the whole idea completely, but I feel I still missing something while I'm setting up the message or when I'm evaluating the bytes from tx sender 
#3
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/30 17:35:50 (permalink)
+1 (1)
You are still making the same mistake in the receive code, i.e. trying to do the checksum on every byte, rather than on the whole block.
Didn't "receive all bytes in the transaction" give you a hint?
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#4
pcbbc
Super Member
  • Total Posts : 1687
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/30 19:40:09 (permalink)
+1 (1)
Receive all bytes in the transaction including the checksum byte.
 
The bytes you have received in the entire message are (data + checksum):
230 + 25 = 255
 
Add the one:
255 + 1 = 256
 
256 % 256 = 0
 
i.e. Message correct
post edited by pcbbc - 2020/03/30 19:44:29
#5
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/30 20:00:13 (permalink)
+1 (1)
Indeed.
The OP's code is changing the U1RXCHK register after every byte.
I think they took the "add 1 to U1RXCHK" instruction too literally.
It meant "take the value in U1RXCHK, and add 1 to it". It did not mean to place the modified value back in the U1RXCHK register.
Similarly in the transmit routine,
   U1TXCHK = ~U1TXCHK;
    UART1_Write(U1TXCHK);

should have been just
    UART1_Write(~U1TXCHK);

 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#6
pcbbc
Super Member
  • Total Posts : 1687
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/30 20:40:35 (permalink)
+1 (1)
Indeed.
But U1RXCHK is a read/write register that only get modified by the hardware if/when you read/write the UART data register.
So their code still “works”, but it’s certainly not how U1RXCHK was intended to be used.
#7
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/30 20:44:07 (permalink)
+1 (1)
pcbbc
...
So their code still “works”,

Not if you modify U1RXCHK after every byte is received.
Yes, it will work if you do that code after all bytes are received, including the checksum byte.
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#8
fabianpi
Starting Member
  • Total Posts : 63
  • Reward points : 0
  • Joined: 2017/03/26 15:30:13
  • Location: 0
  • Status: offline
Re: Checksum in UART from PIC18F27K42 2020/03/30 21:40:47 (permalink)
0
I feel really a fool but I would require a bit more information for this process. 

I've changed the code in order to check what output do I have everytime I receive a byte from the UART buffer.


void receive_rx(void) {
    static int i = 0;
    
    // 3. receive all bytes in the transaction
    d = UART1_Read();
    i++;

    // 4. add 1 to U1RXCHK
    // U1RXCHK = U1RXCHK + 1;
    printf("received byte: %d and checksum %d and indx: %d\r\n", d, U1RXCHK, i);
    
    // if all data was transfered 
    if (i == 2) {
     
        // (U1RXCHK + d == 0) ? printf("%d\r\n", d) : printf("no data available\r\n");
        
        // 1. clear the UxTXCHK register
        i = d = U1TXCHK = 0;
        // 2. Set C0EN bit
        U1CON2bits.C0EN = 1;
        // d = 0;
    }
}

 
and the output from the receiver is: 
received byte: 45 and checksum 115 and index: 1
received byte: 210 and checksum 70 and index: 2
 
Receive all bytes in the transaction including the checksum byte.
 
The bytes you have received in the entire message are (data + checksum):
230 + 25 = 255
 
Add the one:
255 + 1 = 256
 
256 % 256 = 0
 
i.e. Message correct
According to this principle, if I take the bytes of data + checksum from U1TXCHK sender I have
45 + 210 = 255 and then follow the steps from the quote and it will work fine.

But if you notice, I didn't modify the U1RXCHK register in any time, I simply printed and checked the numbers
115 and 70 and I really don't see a relationship between these two numbers and why I need to add 1 to them, because they don't reach 255 or 256 at all. 

Maybe I will have to read a little bit more about how checksums work in this case. 

The real issue here is that if it's working correctly as they way it is, what exactly do I need to do with the U1RXCHK register? 

I feel really stupid but sorry for this kind of confusion from my part, what I'm really trying to do is to learn how it works.
 
#9
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/30 21:44:41 (permalink)
+1 (1)
You are duplicating what the hardware is doing.
Once you have received those two bytes, the value in the U1RXCHK register will be 255.
Just take that value, add one to it, and you will have zero if the checksum is correct.
i.e. you don't have to add up the received values yourself, that is what the U1RXCHK register is doing for you.
 
edit: You got the wrong intermediate value because you removed the code to clear U1RXCHK at the start.
You still need that.
 
post edited by ric - 2020/03/30 21:47:30

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#10
fabianpi
Starting Member
  • Total Posts : 63
  • Reward points : 0
  • Joined: 2017/03/26 15:30:13
  • Location: 0
  • Status: offline
Re: Checksum in UART from PIC18F27K42 2020/03/31 09:33:37 (permalink)
0
edit: You got the wrong intermediate value because you removed the code to clear U1RXCHK at the start.
You still need that.
 
I'm still unable to get the correct intermediate value, this is my current function to check what's the checksum adder output in the printf function.
void receive_rx(void) {
    static int i = 0;
    static uint8_t chksm = 0;
    
    // 1. clear the UxTXCHK register
    U1TXCHK = 0;
    // 2. Set C0EN bit
    U1CON2bits.C0EN = 1;
    // 3. receive all bytes in the transaction
    d = UART1_Read();
    i++; // to count each byte received

    // adding all checksum to a variable
    chksm = chksm + U1RXCHK;

    // I don't altered U1RXCHK to check the output
    printf("received byte: %d and var checksum %d and indx: %d and real checksum %d\r\n", d, chksm, i, U1RXCHK);

    // when all data is received
    if (i == 2) {
        
        // 4. add 1 to U1RXCHK
        chksm++;
        printf("received byte: %d and var checksum %d and indx: %d and real checksum %d\r\n", d, chksm, i, U1RXCHK);
        i = d = chksm = 0; // reset variables
    }
}

 
receive_rx() is called in each loop.
 
and this is the serial output:
received byte: 45 and checksum 115 and indx: 1 and real checksum 115
received byte: 210 and checksum 185 and indx: 2 and real checksum 70

// this is the output after the two bytes are sent
received byte: 210 and checksum 186 and indx: 2 and real checksum 70

post edited by fabianpi - 2020/03/31 09:36:16
#11
pcbbc
Super Member
  • Total Posts : 1687
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/31 12:29:06 (permalink) ☄ Helpfulby fabianpi 2020/03/31 14:35:39
+1 (1)
You’re very confused. As ric says, the hardware automatically adds the value of every byte received to U1RXCHK. You don’t need to do any adding yourself.

1. Set U1RXCHK = 1.
2. Set U1CON2bits.C0EN = 1.
3. Read the data byte(s) from the UART with UART1_Read() - In your case this is just a single byte.
4. Read the checksum byte for the UART with UART1_Read().
5. Finally read U1RXCHK into a byte variable. Add 1 to that byte variable. If the data was received correctly the byte variable should be 0x00, otherwise there was a transmission error.
#12
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/31 12:29:36 (permalink) ☄ Helpfulby fabianpi 2020/03/31 14:35:41
+1 (1)
You clear the wrong register.
U1TXCHK not U1RXCHK
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#13
fabianpi
Starting Member
  • Total Posts : 63
  • Reward points : 0
  • Joined: 2017/03/26 15:30:13
  • Location: 0
  • Status: offline
Re: Checksum in UART from PIC18F27K42 2020/03/31 14:43:13 (permalink)
0
I've solve it!, first of all, I really would like to thank you for taking your time to help me this simple issue. 
 
I made two mistakes with the last code that I posted and I will share what was the issue.
 You clear the wrong register.U1TXCHK not U1RXCHK
1. I was clearing the wrong register, as you stated, is required to clear the U1RXCHK and NOT U1TXCHK. 
 
3. Read the data byte(s) from the UART with UART1_Read() - In your case this is just a single byte.
4. Read the checksum byte for the UART with UART1_Read().
5. Finally read U1RXCHK into a byte variable. Add 1 to that byte variable. If the data was received correctly the byte variable should be 0x00, otherwise there was a transmission error.
 
2. I was not reading all the data in the first loop, when I decided (after a lot of suggestions from your side) to read all the data transfered from 1 MCU to another, the code started to work as supposed to. 

This is the final code for the sender and receiver.
sender code:
void send_tx(void) {
    // 1. clear the UxTXCHK register
    U1TXCHK = 0;
    // 2. Set C0EN bit
    U1CON2bits.C0EN = 1;
    
    // 3. send all bytes of the transaction output
    uint8_t tx = 45; // testing sending '4'
                    // to read it in the other mcu
    UART1_Write(tx);
    
    // 4. Invert UxTXCHK and send the result
    // as the last byte of the transaction.
    UART1_Write(~U1TXCHK);
    
    __delay_ms(2000);
}

 
receiver code:
void receive_rx(void) {
    uint8_t checksum_reg = 0, data = 0, checksum_rx = 0;
    // 1. clear the UxRXCHK register
    U1RXCHK = 0;
    // 2. Set C0EN bit
    U1CON2bits.C0EN = 1;
    // 3. receive all bytes in the transaction
    data = UART1_Read();
    checksum_rx = UART1_Read();
    // 4. Add 1 to U1RXCHK
    checksum_reg = U1RXCHK + 1;
    
    // if the result is '0', the checksum passes, otherwise it fails
    if (checksum_reg == 0)
        printf("received byte: %d | checksum var %d | U1RXCHK var %d\r\n",
                data,
                checksum_rx,
                checksum_reg);
    else
        printf("no valid data received\r\n");
}

 
 
post edited by fabianpi - 2020/03/31 14:47:26
#14
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/31 14:43:30 (permalink)
+1 (1)
pcbbc
1. Set U1RXCHK = 1.

Ah now, if you do that, you don't need to add 1 at the end! ;)
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#15
fabianpi
Starting Member
  • Total Posts : 63
  • Reward points : 0
  • Joined: 2017/03/26 15:30:13
  • Location: 0
  • Status: offline
Re: Checksum in UART from PIC18F27K42 2020/03/31 14:57:45 (permalink)
0
ric
pcbbc
1. Set U1RXCHK = 1.

Ah now, if you do that, you don't need to add 1 at the end! ;)
 



Tried without success :(
#16
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/03/31 15:00:08 (permalink)
+1 (1)
What does "without success" mean?
What value did you get at the end?
It should not matter if the 1 is added at the start or at the end.
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#17
fabianpi
Starting Member
  • Total Posts : 63
  • Reward points : 0
  • Joined: 2017/03/26 15:30:13
  • Location: 0
  • Status: offline
Re: Checksum in UART from PIC18F27K42 2020/04/04 14:41:41 (permalink)
0
The method following the datasheet worked for me.

What did not work was to assign U1RXCHK = 1 at beginning and not adding the 1 at last step. 

So I suggest to follow the datasheet method. 
#18
ric
Super Member
  • Total Posts : 26943
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Checksum in UART from PIC18F27K42 2020/04/04 14:54:26 (permalink)
+1 (1)
That is reasonable advice if it works for you.
 
I would still be curious what the incorrect value was.

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#19
Jump to:
© 2020 APG vNext Commercial Version 4.5