MTSSerial write() functions not blocking as per library documentation
- This topic has 8 replies, 2 voices, and was last updated 8 years, 10 months ago by
Mike Fiore.
-
AuthorPosts
-
May 18, 2016 at 9:03 am #12556
Will Blight
ParticipantI am having a problem sending serial data using the MTSSerial library.
It appears that the library code does not check the status of the TX buffer
before adding additional data.Am I using the correct library of the DragonFly?
Setup
=====
I have the development kit and I am sending the data through the RS232 port
to my PC. I have a program that displays each byte received on the PC.Problem
=======
The documentation in MTSBufferedIO.h says:
/* This method enables bulk writes to the Tx or write buffer.*/
int write(const char* data, int length, unsigned int timeoutMillis);/* This method writes a single byte as a char to the Tx or write buffer. */
/* This method blocks until the byte is written. */
int write(char data);Neither of these two methods block. If I add a delay between
successive calls to write(char) then I correctly receive each
byte on the PC. (Adding delays throws off the timing between
bytes, which makes this method impractical.)Test Program (See below)
========================
This program is configured to send 10 bytes through the RS232 port.
The port is configured as 8 data bits, odd parity, 1 stop bit, 1200 baud.Results
========
If I add a delay between each byte sent, I receive all the data
correctly. If I do not add a delay I get partial data, with the
odd byte being correct.include "mbed.h" include <iostream> include "MTSSerial.h" DigitalOut bc_nce(PB_2); int main() { //Disable the battery charger unless a battery is attached. bc_nce = 1; char Send_Buffer[160]; int i; wait(2); /* Must use MTSSerial to get correct configuration 8O1 serial setting. */ mts::MTSSerial sp(D1,D0); sp.baud(1200); sp.format(8,SerialBase::None,1); for (i=0; i< 10; i++) Send_Buffer[i] = i; /* wait for serial port pin voltage to change. */ wait(1); /* doesn't block. */ sp.write(Send_Buffer,10,200); wait(1); for (i=0; i< 10; i++) { /* The code commented out did not work. The serial port is always */ /* writeable. The serial port txFull is always false. I added */ /* printf statements to test these conditions. */ /* The printf statements have been removed to simplify this code. */ // while (sp.writeable()==0) // while (sp.txFull()==true) //{ /* adding delay between successive writes fixes the TX buffer */ /* overwriting problem. */ wait(0.0096f); //} sp.write(Send_Buffer[i]); } while (1) { /* do nothing */ } }
-
This topic was modified 8 years, 10 months ago by
Will Blight.
May 18, 2016 at 9:36 am #12558Mike Fiore
BlockedWill,
A few things…
1) Try bumping your baud rate up to at least 9600. I don’t think rates slower than that are supported.
2) Looks to me like you are configuring the port for no parity, not odd parity.
3) You aren’t checking the return value of the write function. You don’t really know if it’s failing or succeeding. Also, how are you so sure that the write call isn’t blocking? Even at 1200 baud, sending 10 bytes should take less than 100ms.
4) The default size for both the TX and RX buffers is 256 bytes. TxFull won’t return true until there are 256 bytes in the buffer waiting to be sent. At this point, the write function would also return 0 immediately because the TX buffer is full.
I suggest checking return values and bumping up your band rate. You should not need to wait in between sending bytes, and the write functions should not be overwriting unsent data in the TX buffer.
Cheers,
Mike
May 18, 2016 at 1:05 pm #12561Will Blight
ParticipantHi Mike,
I tested everything again this morning and 1200 baud, no parity, 8 bit works fine. The problem is only with odd parity and I believe I know the reason.I am writing code to communicate with our sensors using the HART protocol.
HART requires 1200 baud, 8 data bits, odd parity and 1 stop bit. (I have a HART C++ library.)
I was testing the communication at different baud rates and parity settings all day yesterday. Your correct the code I provided did not use odd parity (my mistake, posted the wrong code).
Below is a better example of test code I was using.int main() { char Send_Buffer[160]; int i; bc_nce = 1; mts::MTSSerial sp(D1,D0); sp.baud(19200); sp.format(8,SerialBase::Odd,1); //sp.format(8,SerialBase::None,1); for (i=0; i< 10; i++) Send_Buffer[i] = i; wait(1); int sent = 0; for (i=0; i< 10; i++) { while (sp.writeable()==0) { /* wait for room in the buffer */ } while (sp.txFull()==true) { /* wait for room in the buffer */ } while (sent == 0) { sent = sp.write(Send_Buffer[i]); } sent = 0; } while (1) { } }
I think I have found what the problem is. When configuring the serial port with parity enabled, there are 2 options. In the STM32F411RE reference manual (see section 19.3.7 parity control) the USART frame can contain 7 or 8 data bits plus the parity bit. I have included the table from the reference manual below.
Table 84. Frame formats
Mbit PCE bit USART frame(1) 0 0 | SB | 8 bit data | STB | 0 1 | SB | 7-bit data | PB | STB | 1 0 | SB | 9-bit data | STB | 1 1 | SB | 8-bit data PB | STB |
Legends:
M: M bit, P: PCE bit, SB: start bit, STB: stop bit, PB: parity bit,The second and forth row have parity enabled. I need serial port configure like the forth row.
I believe the MTSSerial library is configuring the USART using the second row (7 data bits + parity bit). To test this theory I changed my PC software to expect 7 data bits plus an odd parity bit. The results: I received the data correctly every time.This would explain why the data appears corrupt and bytes are missing.
How do I set the M bit and the PCE bit from my C++ code? Where would I insert that into my code when using the MTSSerial library.
-
This reply was modified 8 years, 10 months ago by
Will Blight.
-
This reply was modified 8 years, 10 months ago by
Will Blight.
-
This reply was modified 8 years, 10 months ago by
Will Blight.
-
This reply was modified 8 years, 10 months ago by
Will Blight.
-
This reply was modified 8 years, 10 months ago by
Will Blight.
May 18, 2016 at 1:24 pm #12568Mike Fiore
BlockedWill,
That makes more sense. Sounds like if you configure for 8 data bits with the parity bit, you actually get 7 data bits + 1 parity bit (total of 8 bits per word). If you need 8 data bits + 1 parity bit, try using 9 instead of 8 for the data bits in your format call. I think that might get you what you want.
Cheers,
Mike
May 19, 2016 at 8:05 am #12599Will Blight
ParticipantHi Mike,
I tried using 9 in the format call but it didn’t work. Literally, it didn’t work I had no serial communication using a 9. The function documentation states 5 to 8 bits. I have found the bit to use and the register:
USART_CR1 |= USART_CR1_PCE;
but I am not sure where to use the code. It doesn’t compile if just add it. I am searching through the library source code looking for the correct header files to add.But, the STM32F411xE can have up to 3 USARTs. Which USART I need to change will be related to the serial port object created. But how to access the registers of that object is unclear.
-
This reply was modified 8 years, 10 months ago by
Will Blight.
May 19, 2016 at 9:02 am #12604Mike Fiore
BlockedWill,
Pins D0/PA_3 and D1/PA_2 are muxed to USART2 according to table 9, Alternate Function Mapping, of the STM32F411RE datasheet.
Try adding the following line after your sp.format() line
USART2->CR1 |= USART_CR1_PCE;
Hope this helps!
Cheers,
Mike
-
This reply was modified 8 years, 10 months ago by
Mike Fiore.
May 19, 2016 at 11:39 am #12608Will Blight
ParticipantHi Mike,
I finally got it working. You cannot change the the PCE bit after calling format. You need to replace the format function by setting each of the bits that format would normally set.// sp.format(8,SerialBase::Odd,1); USART2->CR1 |= USART_CR1_PCE; //enable parity USART2->CR1 |= USART_CR1_M; // set to 9 data bits USART2->CR1 |= USART_CR1_PS; //odd parity.
Thanks for the help.
Will.May 19, 2016 at 11:42 am #12609Will Blight
ParticipantTo finish off the configuration the stop bits can also be configured using.
USART2->CR2 |= USART_CR2_STOP_0;/*!<Bit 0 */ USART2->CR2 |= USART_CR2_STOP_1;/*!<Bit 1 */
May 19, 2016 at 12:10 pm #12610Mike Fiore
BlockedWill,
I didn’t have the setup to actually test the code I posted, so I apologize that it didn’t work. I’m glad you were able to get things working!
Let us know if you have any other issues!
Cheers,
Mike
-
This topic was modified 8 years, 10 months ago by
-
AuthorPosts
- You must be logged in to reply to this topic.