MTSSerial write() functions not blocking as per library documentation

Home Forums Dragonfly MTSSerial write() functions not blocking as per library documentation

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #12556
    Will Blight
    Participant

    I 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 7 years, 11 months ago by Will Blight.
    #12558
    Mike Fiore
    Blocked

    Will,

    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

    #12561
    Will Blight
    Participant

    Hi 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 7 years, 11 months ago by Will Blight.
    • This reply was modified 7 years, 11 months ago by Will Blight.
    • This reply was modified 7 years, 11 months ago by Will Blight.
    • This reply was modified 7 years, 11 months ago by Will Blight.
    • This reply was modified 7 years, 11 months ago by Will Blight.
    #12568
    Mike Fiore
    Blocked

    Will,

    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

    #12599
    Will Blight
    Participant

    Hi 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 7 years, 11 months ago by Will Blight.
    #12604
    Mike Fiore
    Blocked

    Will,

    Pins D0/PA_3 and D1/PA_2 are muxed to USART2 according to table 9, Alternate Function Mapping, of the STM32F411RE datasheet.

    http://www.st.com/content/ccc/resource/technical/document/datasheet/b3/a5/46/3b/b4/e5/4c/85/DM00115249.pdf/files/DM00115249.pdf/jcr:content/translations/en.DM00115249.pdf

    Try adding the following line after your sp.format() line

    
    USART2->CR1 |= USART_CR1_PCE;
    

    Hope this helps!

    Cheers,

    Mike

    • This reply was modified 7 years, 11 months ago by Mike Fiore.
    #12608
    Will Blight
    Participant

    Hi 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.

    #12609
    Will Blight
    Participant

    To 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 */
    
    #12610
    Mike Fiore
    Blocked

    Will,

    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

Viewing 9 posts - 1 through 9 (of 9 total)
  • You must be logged in to reply to this topic.