Implementing MB RTU on a Renesas QSK62P board

  • Thread starter Timothy Burgess
  • Start date
T

Thread Starter

Timothy Burgess

To begin, I guess I should describe what I'm doing...
Long story short, I'm programming a Renesas QSK62P board to periodically pull data from a machine's microcontroller and storing the data temporarily to then be retrieved and stored permanently by an outside source.

I guess the best way to explain my method would be to go ahead and include relevant C code (which is relatively simple) with some detailed comments so that whoever reads this knows exactly what's going on.

I'm using two different UARTs on the board... one is for the +5v to +12v output and the other is for the inverted 0 to -7v output.


/* global variables */
char u0_in; // declare UART0 recieve variable

/* variables for modbus */
int slave_dev_addr = 16; // declare slave device address variable
int func_code = 3; // declare function code variable
int reg_addr = 266; // declare register address variable
int num_regs = 1; // declare number of registers variable


main loop:

/* if switch 3 is pressed... (for testing purposes) */
if (!S3) {

pd1_0 = pd1_1 = 1; //sets port direction to output so that machine can be queried

/* the following code should send the proper query through UART0 and UART2

note:
u0tb stands for uart0 transmit buffer
ti_u0c1 is the buffer empty flag (bit)
crcin is the register for the CRC calculator built in to the QSK62P board
crcd is the CRC calculator's output register
(I've been meaning to make sure the board's CRC algorithm is the same as used on the machine but haven't gotten around to it yet... I at least want a response from the machine first...)
*/
u0tb = func_code; // send function code
u2tb = func_code; // send function code
crcin = func_code;
while((ti_u0c1 == 0)&&(ti_u2c1 == 0)); // make sure transmit is complete
u0tb = slave_dev_addr; // send slave address
u2tb = slave_dev_addr; // send slave address
crcin = slave_dev_addr;
while((ti_u0c1 == 0)&&(ti_u2c1 == 0)); // make sure transmit is complete
u0tb = reg_addr; // send register address
u2tb = reg_addr; // send register address
crcin = reg_addr;
while((ti_u0c1 == 0)&&(ti_u2c1 == 0)); // make sure transmit is complete
u0tb = num_regs; // send number of registers to return
u2tb = num_regs; // send number of registers to return
crcin = num_regs;
while((ti_u0c1 == 0)&&(ti_u2c1 == 0)); // make sure transmit is complete
u0tb = crcd;
u2tb = crcd;
while((ti_u0c1 == 0)&&(ti_u2c1 == 0)); // make sure transmit is complete

pd1_0 = pd1_1 = 0; //sets port direction to input and wait for response from the machine

while(ri_u0c1 == 0); // make sure receive is complete
//u0_in = (char) u0rb; // read in received data
/* tried it without char in a desperate attempt lol */
u0_in = u0rb; // read in received data

IntToAsciiDec(lcd_text,4,u0_in);
DisplayString(LCD_LINE2, lcd_text);
// so that the data can be displayed on the super hi-res lcd screen (lol)

}

/* I do realize that using a queuing method to transmit is the better way to send the bitstream but the above method should still work, right? */


UART initialization:

/* hopefully everything lines up for you so you know which bits are which...
there are multiple lines of the same variable (with all commented but 1) because I was trying different combinations */

//ucon = 0x00; // UART transmit/receive control register 2
ucon = 0x40; // UART transmit/receive control register 2
/*
00000000; // transmit irq not used
||||||||______UART0 transmit irq cause select bit, U0IRS
|||||||_______UART1 transmit irq cause select bit, U1IRS
||||||________UART0 continuous receive mode enable bit, U0RRM - set to 0 in UART mode
|||||_________UART1 continuous receive mode enable bit, U1RRM - set to 0 in UART mode
||||__________CLK/CLKS select bit 0, CLKMD0 - set to 0 in UART mode
|||___________CLK/CLKS select bit 1, CLKMD1 - set to 0 in UART mode
||____________Separate CTS/RTS bit, RCSP
|_____________Reserved, set to 0 */

u0brg = (unsigned char)(((XIN_FREQ/16)/BAUD_RATE)-1); // set UART2 bit rate generator
/*
bit rate can be calculated by:
bit rate = ((BRG count source / 16)/baud rate) - 1
bit rate = ((12MHz/16)/19200) - 1 = 38

** one has to remember that the value of BCLK does not affect BRG count source */

u0c0 = 0x10; // UART0 transmit/receive control register 0
//u0c0 = 0x04; // UART0 transmit/receive control register 0
//u0c0 = 0x14; // UART0 transmit/receive control register 0
/*
00000000; // f1 count source, CTS/RTS enabled, CMOS output
||||||||______BRG count source select bit, CLK0
|||||||_______BRG count source select bit, CLK1
||||||________CTS/RTS function select bit, CRS
|||||_________Transmit register empty flag, TXEPT
||||__________CTS/RTS disable bit, CRD
|||___________Data output select bit, NCH
||____________CLK polarity select bit, CKPOL - set to 0 in UART mode
|_____________Transfer format select bit, UFORM - set to 0 in UART mode */

u0c1 = 0x05; // UART0 transmit/receive control register 1
//u0c1 = 0x45; // UART0 transmit/receive control register 1
/*
00000101; // enable transmit and receive
||||||||______Transmit enable bit, TE
|||||||_______Transmit buffer empty flag, TI
||||||________Receive enable bit, RE
|||||_________Receive complete flag, RI
||||__________Reserved, set to 0
|||___________Reserved, set to 0
||____________Data logic select bit, U0LCH
|_____________Error signal output enable bit, U0ERE */

//u0mr = 0x05; // UART0 transmit/receive mode register, not reversed
u0mr = 0x85; // UART0 transmit/receive mode register, reversed
/*
10000101; // 8-bit data, internal clock, 1 stop bit, no parity
||||||||______Serial I/O Mode select bit, SMD0
|||||||_______Serial I/O Mode select bit, SMD1
||||||________Serial I/O Mode select bit, SMD2
|||||_________Internal/External clock select bit, CKDIR
||||__________Stop bit length select bit, STPS
|||___________Odd/even parity select bit, PRY
||____________Parity enable bit, PRYE
|_____________TxD, RxD I/O polarity reverse bit */

u0tb = u0rb; // clear UART0 receive buffer by reading
u0tb = 0; // clear UART0 transmit buffer

u2brg = (unsigned char)(((XIN_FREQ/16)/BAUD_RATE)-1); // set UART2 bit rate generator
/*
bit rate can be calculated by:
bit rate = ((BRG count source / 16)/baud rate) - 1

** one has to remember that the value of BCLK does not affect BRG count source */

u2c0 = 0x10; // UART2 transmit/receive control register 0
//u2c0 = 0x04; // UART2 transmit/receive control register 0
//u2c0 = 0x14; // UART2 transmit/receive control register 0
/*
00000100; // f1 count source, CTS/RTS enabled, CMOS output
||||||||______BRG count source select bit, CLK0
|||||||_______BRG count source select bit, CLK1
||||||________CTS/RTS function select bit, CRS
|||||_________Transmit register empty flag, TXEPT
||||__________CTS/RTS disable bit, CRD
|||___________Data output select bit, NCH
||____________CLK polarity select bit, CKPOL - set to 0 in UART mode
|_____________Transfer format select bit, UFORM - set to 0 in UART mode */

//u2c1 = 0x05; // UART0 transmit/receive control register 1
u2c1 = 0x45; // UART0 transmit/receive control register 1
/*
01000101; // enable transmit and receive
||||||||______Transmit enable bit, TE
|||||||_______Transmit buffer empty flag, TI
||||||________Receive enable bit, RE
|||||_________Receive complete flag, RI
||||__________Reserved, set to 0
|||___________Reserved, set to 0
||____________Data logic select bit, U2LCH
|_____________Error signal output enable bit, U2ERE */

u2mr = 0x85; // UART0 transmit/receive mode register, reversed
/*
10000101; // 8-bit data, internal clock, 1 stop bit, no parity
||||||||______Serial I/O Mode select bit, SMD0
|||||||_______Serial I/O Mode select bit, SMD1
||||||________Serial I/O Mode select bit, SMD2
|||||_________Internal/External clock select bit, CKDIR
||||__________Stop bit length select bit, STPS
|||___________Odd/even parity select bit, PRY
||____________Parity enable bit, PRYE
|_____________TxD, RxD I/O polarity reverse bit */

u2tb = u2rb; // clear UART2 receive buffer by reading
u2tb = 0; // clear UART2 transmit buffer

DISABLE_IRQ // disable irqs before setting irq registers
s0ric = 0x04; // Enable UART0 receive interrupt, priority level 4
s2ric = 0x05; // Enable UART2 receive interrupt, priority level 4
ENABLE_IRQ // Enable all interrupts



I'm unsure as to exactly what the problem is but here is what I think it could be:

1) The 2 outputs are not matching opposites and/or the output voltage(s) are not the right ranges. I'm 99% certain the voltages aren't right but I'm not sure how much it REALLY matters as long as the difference is right.

2) Nothing actually gets transmitted from the outputs (I'm in the process of obtaining a logic analyzer so I can make sure it's sending out what I tell it to...)

3) The CRC algorithm doesn't match but one would think that I would at least get some kind of response regardless, right?


A little background info. on myself so that you will know on what level you should to talk to me: I'm relatively inexperienced with modbus and serial communications, being that I'm 21 years old and on my last semester of computer engineering (Bachelor's). I've had a semester's worth (8 projects) of embedded systems and dealing with this particular board (QSK62P)... 2 or 3 of which involved UART but none of which involved using UART to communicate with anything another than another QSK62P board.


I really appreciate the help!!!


Tim
 
E

Elmer Bulman

You will not get a response from a Modbus slave if the CRC is in error, it will be assumed to be noise and discarded. And on the subject of CRCs, one important detail I cannot pick out of your description is the need to seed a Modbus CRC generator with 0xffff for the Modbus CRC calc. Your example poll in Hex should be:
POLL: 10 03 01 0a 00 01 a6 b5
 
C

Curt Wuollet

Nicely written code, I suggest you datascope something that _can_ communicate with the intended device and then compare with what you are sending. It could well be some nuance (and they are legion in serial comms) that is upsetting the beast. This would at least separate software issues from hardware issues. You don't need a logic analyzer, a good free terminal program should show if you have the bits right and a free datascope program will tell all about the exchange.

Regards
cww
 
L

Lynn August Linse

Elmer's reply is CRITICAL & HELPFUL ... ALWAYS use someone else's test tool to confirm an exact Modbus poll which is valid; use someone else's CRC and confirm your own request is exactly the same. You'd be a fool to waste even 5 minutes debugging your C code if you are sending the WRONG CRC. For example, people often put the 2 bytes of the 16-bit in the WRONG order ... because the correct order seems the wrong way but isn't.
 
Top