PIC32 UART sends garbage characters after initialization - c

I'm writing code to configure the serial port on a pic32 family device. The initialization appears to work for the most part, but I get garbage data in place of the first 6 characters that I write. I noticed, however, that if I add an arbitrarily long wait at the end of the initialization function, this goes away. Is there some register flag that I need to be waiting on at the end of my initialization? My initialization code is below. If it helps, I am basing this initialization off of the UART section in the pic32 reference manual. I added the code below for my transmission function as well. My expected output string is "Hello from the bootloader code.\r\n" but the actual bytes I get are:
00000000 00 00 aa b1 b1 bd 81 66 72 6f 6d 20 74 68 65 20 |.......from the |
00000010 62 6f 6f 74 6c 6f 61 64 65 72 20 63 6f 64 65 2e |bootloader code.|
00000020 0d 0a
void initializeUART2()
{
uint32 counter;
initialized = TRUE;
U2MODE = 0;
U2STA = 0;
U2BRG = 0;
IEC1bits.U2TXIE = 0;
IEC1bits.U2RXIE = 0;
IEC1bits.U2EIE = 0;
//disable UART transmission before config
U2STA &= ~UART_TRANSMIT_ENABLED_STATUS_FLAG;
//disable UART before config
U2MODE &= ~UART_ENABLED_MODE_FLAG;
RS232_RS485_TRIS=0; //set to output
RS232_RS485=0; //select RS-232 mode on MAX3161
//set baudrate BAUDRATE = CLOCK_FREQUENCY/(16*(U2BRG + 1))
//solve for U2BRG value
U2BRG = (UINT16)(((PERIPHERAL_CLOCK_FREQUENCY/UART2_BAUDRATE)/16)-1);
//set mode to 8 bit no parity
U2MODE &= ~UART_PARITY_DATA_MODE_BITS;
//set number of stop bits to 1
U2MODE &= ~UART_EXTRA_STOP_MODE_BIT_FLAG;
//enable the UART port
U2MODE |= UART_ENABLED_MODE_FLAG;
//enable serial transmission
U2STA |= UART_TRANSMIT_ENABLED_STATUS_FLAG;
//without this loop, I get garbage in first 6 bytes of my first message
counter = 1000;
while(counter--);
}
void putUART2(uint32 value)
{
if(!initialized)
{
initializeUART2();
}
//make sure value is in range of writable values
value &= UINT32_MASK(8);
//clear transmit interrupt flag
IFS1bits.U2TXIF = 0;
//wait for the transmit buffer to be empty
while((U2STA & UART_TRANSMIT_STATUS_FLAG) == 0);
//set the data byte to be written in the write register
//also starts transmission
U2TXREG = value;
//wait for the transmit buffer to be empty
//both of these waits are necessary to avoid missing bytes
while((U2STA & UART_TRANSMIT_STATUS_FLAG) == 0);
}

The MAX3161 needs at least 100 ns to stabilize after switching modes to RS232.
Also, these lines:
RS232_RS485_TRIS=0; //set to output
RS232_RS485=0; //select RS-232 mode on MAX3161
should be reversed; set the output, then the direction register to avoid glitches.

Suspect the MAX3161 chip, which has charge pumps, needs the additional time to reach stable operating voltages.
It may be only for a bit time or 2, but if a message is sent too early, the serial output is messed until a quiet time occurs.
Lesser candidate: problem is an interaction between this and the unposted send routine.
Note: It's amazing how seeing using info like the unposted "garbage data" may help. Also knowing what the "good" first 6 bytes or so is useful.
[Edit] #Doug Currie is on the right track.
When RS232_RS485_TRIS1 is changed to output, a delay time as he suggest is needed before data is sent. This applies here as well as other place in code.
Further, before RS232_RS485_TRIS1 is changed to input, code needs to insure all the data is completely transmitted. This may be a 10/baud after the the PIC declares the xmit buffer empty. Or check the proper xmit status bit before turning the bus around. (Shift Register empty - names vary depending on compiler.)

Related

I2C ACKEN Bit doesnt get cleared by hardware

I am using a PIC16F1789 and an MPU-9250. The Code inside my I2C Reading funciton looks like this:
unsigned char i2cSensor_Read(unsigned char regAddr){
unsigned char val;
// Start
i2cWait();
SEN = 1;
// Address + Write Bit
i2cWait();
SSP1BUF = ((slvAdd<<1) | (0b0<<0)); // address slave + write (0)
i2cWait();
//Register address
SSP1BUF = regAddr; // address register
i2cWait();
//Start
RSEN = 1;
i2cWait();
// Address + Read Bit
SSP1BUF = ((slvAdd<<1) | (0b1<<0)); //Address + read (1)
i2cWait();
// Read data
RCEN = 1;
i2cWait();
val = SSP1BUF;
ACKDT = 1; // set acknowlege Bit (1 = Not Acknowlege, 0 = Acknowlege)
ACKEN = 1; // send acknowlege Bit
// Stop
i2cWait();
PEN = 1;
return val;
}
When calling the last i2cWait(), the program hangs.
The wait function looks like this:
void i2cWait(){
while((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F));
}
I've worked with the "Single-Byte Read Sequence" on page 35 of the 9250 Datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/5/5/0/MPU9250REV1.0.pdf
And the PIC Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/40001675C.pdf
When debugging, the program gets stuck in the i2cWait() after I send the NACK Bit. It gets stuck because the ACKEN Bit (Bit 4) of the SSPCON2 register (Page 341 of PIC datasheet) doesn't get cleared, so the program gets stuck in the while().
Why is this the case? Does the Slave have to clear this bit? Is the slave device broken?
I think the issue is really the BF flag is still set and not allowing the ack to be clocked out. As soon as you set RCEN, the BF flag is cleared, thus the call to wait does nothing and val probably contains old data, not new. After 8 clocks, the BF flag is then set and SSP1BUF has the new data. Again, the issue is that BF is set because you didn't read the data buffer after receiving the data, thus the baud rate generator (clock source) is suspended:
"the contents of the SSPSR are loaded into the SSPBUF, the BF flag bit
is set, the SSP1IF flag bit is set and the Baud Rate Generator is
suspended from counting, holding SCL low. The MSSP is now in Idle
state awaiting the next command. When the buffer is read by the CPU,
the BF flag bit is automatically cleared. The user can then send an
Acknowledge bit at the end of reception by setting the Acknowledge
Sequence Enable, ACKEN bit of the SSPCON2 register."
To fix this, you should poll the BF flag looking for a true after you write RCEN.
There are other issues, such as the wait after writing to SEN probably does nothing either, since writing to SEN only SSP1IF bit (SSP1IF is set by hardware on completion of the Start. )

How to use UART receive data for further processing rather than just echoing in embedded C?

Here is the code from my test environment. it simply replies back (echo) the entered data to the terminal application where it is connected through a Serial Port. So far so good.
Now, I need to use that data and process as per the requirements/protocol.
But, I am struggling to consume the data UART0Buffer as I expected.
(The variable UART0Buffer is populated in the UART Interrupt)
I send e.g. "7E0007AA010203040506CC" from the terminal
and the code replies back this to the terminal application in an order in four steps for some reason;
1 by Process #1
37
2 by Process #2
00
3 by Process #1
30 30 30 37 41 41 30 31 30 32 30 33 30 34 30
4 by Process #2
A1
As you can also notice that the data replied (echoed) is not identical with what I send from the terminal.
And furthermore, if I remove line "Process #2" completely,
I can get a proper echo;
37 45 30 30 30 37 41 41 30 31 30 32 30 33 30 34 30 35 30 36 43 43
What am I really missing here?
int main()
{
SystemInit(); /* Clock and PLL configuration */
UARTInit(0, 57600); /* baud rate setting */
while(1)
{
if ( UART0Count != 0 )
{
LPC_UART0->IER = IER_THRE | IER_RLS; /* Disable RBR */
UARTSend( 0, (uint8_t *)UART0Buffer, UART0Count ); // Process #1
UART0Count = 0;
// I need to call a function here in order to process data in UART0Buffer
// like checking/using STX, CHKSUM and DATA.
// A test, if I can manage to use the data in pieces
UARTSend( 0, (uint8_t *)UART0Buffer[0], 1); // Process #2
LPC_UART0->IER = IER_THRE | IER_RLS | IER_RBR; /* Re-enable RBR */
}
}
}
void UARTSend( uint32_t portNum, uint8_t *BufferPtr, uint32_t Length )
{
if ( portNum == 0 )
{
while ( Length != 0 )
{
/* THRE status, contain valid data */
while ( !(UART0TxEmpty & 0x01) );
LPC_UART0->THR = *BufferPtr;
UART0TxEmpty = 0; /* not empty in the THR until it shifts out */
BufferPtr++;
Length--;
}
}
}
EDIT:
As dude has already explained the wrong use of "Process #2", please ignore it. It somehow breaks things. However, my issue persists. Although I can get an echo by "Process #1", I couldn't manage to read and use the data!?! Any pointers would be greatly appreciated.
EDIT:
Receiving:
void UART0_IRQHandler (void)
{
uint8_t IIRValue, LSRValue;
uint8_t Dummy = Dummy;
IIRValue = LPC_UART0->IIR;
IIRValue >>= 1; /* skip pending bit in IIR */
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
{
LSRValue = LPC_UART0->LSR;
/* Receive Line Status */
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
{
/* There are errors or break interrupt */
/* Read LSR will clear the interrupt */
UART0Status = LSRValue;
Dummy = LPC_UART0->RBR; /* Dummy read on RX to clear
interrupt, then bail out */
return;
}
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
{
/* If no error on RLS, normal ready, save into the data buffer. */
/* Note: read RBR will clear the interrupt */
UART0Buffer[UART0Count] = LPC_UART0->RBR;
UART0Count++;
if ( UART0Count == BUFSIZE )
{
UART0Count = 0; /* buffer overflow */
}
}
}
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
{
/* Receive Data Available */
UART0Buffer[UART0Count] = LPC_UART0->RBR;
UART0Count++;
if ( UART0Count == BUFSIZE )
{
UART0Count = 0; /* buffer overflow */
}
}
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
{
/* Character Time-out indicator */
UART0Status |= 0x100; /* Bit 9 as the CTI error */
}
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
{
/* THRE interrupt */
LSRValue = LPC_UART0->LSR; /* Check status in the LSR to see if
valid data in U0THR or not */
if ( LSRValue & LSR_THRE )
{
UART0TxEmpty = 1;
}
else
{
UART0TxEmpty = 0;
}
}
}
You're basically designing a serial message driver. Divide the design into layers.
The lowest layer is the UART driver that moves characters to and from the hardware UART. The UART driver encapsulates all the knowledge about how to interface to the UART hardware. This layer knows nothing of frames or messages, only characters. It copies a transmit character to the TX register when a transmit character is available and the UART is ready to transmit. It copies a received character from the UART RX register when one is available. These actions are typically implemented in the UART interrupt service routine. And typically, RAM circular buffers are used to store the TX and RX characters.
The next layer is for framing characters. This layer is responsible for identifying the characters that delimit a frame. This layer encapsulates all the knowledge about characters are delimited into frames. This is typically implemented as a state machine that gets repeatedly called when characters are available in the RX buffer. The state machine gets the next character from the RX buffer and processes it according to the current state. States might include, for example, waiting_for_start_of_frame, copying_body_of_frame, and waiting_for_end_of_frame. If the frame protocol includes a frame check sequence then this layer performs the check. This layer doesn't attempt to interpret the meaning of frames, rather it just forms complete frames to be used by the next layer.
If your serial messages are large enough to span multiple frames then you might have a layer here that stitches frames together into messages. Or if each message is a contained within a single frame then you probably don't need this layer.
At the top is the layer that actually interprets the message and performs the appropriate actions. This layer doesn't know anything about the UART or the frame delimiters because all of that knowledge is encapsulated by the lower layers.
This answer has more tips, Embedded C UART conventions

Linux inserting carriage return-linefeed instead of just linefeed

I am writing ASCII commands over a UART interface in an embedded linux system.
I tested the code with a laptop to begin with. Both the embedded platform and the laptop share a ftdi usb dongle. The code should be identical on the two platforms (I thought).
I am creating a string and sending it like so,
char cmd[MAX_STR_LEN];
sprintf(cmd,"r %02x %02x\n",chipAddr,naddr);
ssize_t bytes_tx = write(fd, (char *)cmd, strlen(cmd));
if (bytes_tx < 0){
ERROR_PRINT("%s\n",strerror(errno));
return -1;
}
When I monitor the output of the serial device on an oscilloscope when running the code from the PC I see that \n is correctly interpreted as 0x0a.
When I run the same code snippet on the embedded platform I see \n is being interpreted as 0x0d 0x0a or \r\n.
How do I force the embedded platform to send only \n or 0x0a? The embedded platform is running Linux Kernel 4.4.x generated with buildroot.
--- UPDATED Full Test Code
Placed full code here : https://pastebin.com/5dWhaaDv
result on both embedded and laptop targets,
Connected to /dev/ttyUSB0
strlen 8 : r 40 00
tx cmd[0] = 72 r
tx cmd[1] = 20
tx cmd[2] = 34 4
tx cmd[3] = 30 0
tx cmd[4] = 20
tx cmd[5] = 30 0
tx cmd[6] = 30 0
tx cmd[7] = 0a
bytes_tx = 8
sizeof(\n) : 4
The issue was with not properly setting the termios struct flag : c_oflag
From the termios docs ( https://en.wikibooks.org/wiki/Serial_Programming/termios )
//
// Output flags - Turn off output processing
//
// no CR to NL translation, no NL to CR-NL translation,
// no NL to CR translation, no column 0 CR suppression,
// no Ctrl-D suppression, no fill characters, no case mapping,
// no local output processing
//
// config.c_oflag &= ~(OCRNL | ONLCR | ONLRET |
// ONOCR | ONOEOT| OFILL | OLCUC | OPOST);
config.c_oflag = 0;
It was apparently initialized on one platform but not the other. Thanks to #KamilCuk and #EugeneSh. for finding the issue.

Modbus functional code 1 & crc check for PIC microcontoller

I need help in calculating modbus CRC check for function code 1. I.e read coil register. I have sample code for CRC check for function code 3 i.e holding register for analog input.
# Read Coil Status (FC=01)
## Request
This command is requesting the ON/OFF status of discrete coils # 20 to 56
from the slave device with address 17.
11 01 0013 0025 0E84
11: The Slave Address (17 = 11 hex)
01: The Function Code (read Coil Status)
0013: The Data Address of the first coil to read. (Coil 20 - 1 = 19 = 13 hex)
0025: The total number of coils requested. (coils 20 to 56 = 37 = 25 hex)
0E84: The CRC (cyclic redundancy check) for error checking.
Response
11 01 05 CD6BB20E1B 45E6
11: The Slave Address (17 = 11 hex)
01: The Function Code (read Coil Status)
05: The number of data bytes to follow (37 Coils / 8 bits per byte = 5 bytes)
CD: Coils 27 - 20 (1100 1101)
6B: Coils 35 - 28 (0110 1011)
B2: Coils 43 - 36 (1011 0010)
0E: Coils 51 - 44 (0000 1110)
1B: 3 space holders & Coils 56 - 52 (0001 1011)
45E6: The CRC (cyclic redundancy check).
Read Holding Registers (FC=03)
Request
This command is requesting the content of analog output holding registers # 40108 to
40110 from the slave device with address 17.
11 03 006B 0003 7687
11: The Slave Address (17 = 11 hex)
03: The Function Code (read Analog Output Holding Registers)
006B: The Data Address of the first register requested. (40108-40001 = 107 = 6B hex)
0003: The total number of registers requested. (read 3 registers 40108 to 40110)
7687: The CRC (cyclic redundancy check) for error checking.
Response
11 03 06 AE41 5652 4340 49AD
11: The Slave Address (17 = 11 hex)
03: The Function Code (read Analog Output Holding Registers)
06: The number of data bytes to follow (3 registers x 2 bytes each = 6 bytes)
AE41: The contents of register 40108
5652: The contents of register 40109
4340: The contents of register 40110
49AD: The CRC (cyclic redundancy check).
I am no issue for getting response for FC3. because i am sending properly the 2 byte address , but i dont know how can i send single byte and modify crc function for FC1 ->read coil register
Discription of read coil register
unsigned int crc_fn(unsigned char *dpacket,unsigned int len) { // CRC Function(Error calcualtion)
unsigned int crc = 0xffff,poly = 0xa001;
unsigned int i=0;
for(i=0; i<len; i++) {
crc^= dpacket[i];
for(j=0; j<8; j++) {
if(crc & 0x01) {
crc >>= 1;
crc ^= poly;
} else
crc >>= 1;
}
}
return (crc);
}
CRC is normally appended to a message most significant byte first. You need to swap two lines of code, sending the high order byte of the 16 bit crc before the low order byte. Try this change:
Serial_1_Send_byte((unsigned char)(crc1>>8));
Serial_1_Send_byte((unsigned char)crc1);

Modbus TCP - Arduino

I have to implement a Modbus TCP using a TI Launchpad board which is similar to Arduino. I have the following snippet.
MbmByteArray[0] = 0x00;
MbmByteArray[1] = 0x01;
MbmByteArray[2] = 0x00;
MbmByteArray[3] = 0x00;
MbmByteArray[4] = 0x00;
MbmByteArray[5] = 0x0B;
MbmByteArray[6] = 0x01;
MbmByteArray[7] = 0x10;
MbmByteArray[8] = 0x00;
MbmByteArray[9] = 0x00;
MbmByteArray[10] = 0x00;
MbmByteArray[11] = 0x02;
MbmByteArray[12] = 0x04;
MbmByteArray[13] = 0x00;
MbmByteArray[14] = 0x08;
MbmByteArray[15] = 0x00;
MbmByteArray[16] = 0x00;
Serial.println("Written:");
for(int i=0;i<MbmByteArray[5]+6;i++) {
int a=0;
a = MbmClient.write(MbmByteArray[i]);
if(a)
{
// if something is written to the client I check what it is !
Serial.println(MbmByteArray[i]);
}
}
This is my client
You can see that the bytes are not received continuously. But my entire array is like a command to the client. Is there anyway to get it this way :
2016-06-17 14:28:00.252: Session created
2016-06-17 14:28:00.254: Session opened
2016-06-17 14:28:00.256: 17 bytes received
00 01 00 00 00 0B 01 10 00 00 00 02 04 00 07 00 00
2016-06-17 14:28:00.269: 12 bytes sent
< 00 01 00 00 00 06 01 10 00 00 00 02
Please help!
In general, when doing communication on any given line, file or media, you risk breaking up the data. Ethernet actually has a package size (MTU) that can/will be delivered unbroken. But that's another story. It'll be better if you deal with the issue, no matter protocol, hardware or platform. (Or at least be aware of it.)
When you read your ModbusTCP, you should make something like the following pseudo:
//read all ModbusTCP header
while less than 6 bytes received and not timed out and not error
read bytes
//read data
data_length = modbustcp_header position 5 and 6
while less than data_length and not timed out and not error
read bytes
The above function will collect the whole package, before "releasing" it to your engine. The algorithm will work for both sides of your setup. (Both the Texas hw and the PC.)
You could also (most likely) fiddle with the TI TCP stack and make it return bigger blocks. And I guess this was what you were asking for. But again, I wouldn't recommend going down that road.
Thank you Illishar !
I found a way to do it. In Arduino there is a client function, that could send the entire array without sending one value at a time.
byte command[17] = {0x00,0x01,0x00,0x00,0x00,0x0B,0x01,0x10,0x00,0x00,0x00,0x02,0x04,0x00,0x07,0x00,0x00};
MbmClient.write(command,17);
This client.write(buffer,number of elements) helps me to send the entire content in a single packet. It works like a charm :)

Resources