cancel
Showing results for 
Search instead for 
Did you mean: 

Does ST have any control over the serial comm protocol?

Posted on December 17, 2014 at 01:51

I'm quite sure that I don't understand the expected use of the SPWF01 modules. Perhaps I've been doing this stuff too long and have become a crufty old guy, but the command/response protocol seems like it's written expecting a human on the end of the serial port instead of a micro. Help me out here.

Here's the problem; the wifi modules have a response structure that is great for humans but a tad odd for parsing by computers. If I was to use the facilities of C for a parser, I would use something like gets() to get input up to the end of line. The module prepends cr/lf to its responses, so it looks great on hyperterm, but it terminates a gets() call before getting to any actual data. So, I have to bring in a ''whole bunch'' of data and parse it. The alternatives are to know the number of characters to expect, keep reading until you hit a terminator, or wait for a timeout.

Okay, bring in a bunch of data and look for the terminator. The terminator comes first, then a bunch of data, then a terminator. Well, that's going to be a weird parser, do two pieces perhaps, but what if it isn't a response. AND all of this stuff is coming ''in band'' with my application data being transferred. If the module messages had some kind of ''escape sequence'' in front of them instead of cr/lf I could write a parser for that. 

The messages don't have a standard length of response, so you can't just use a read X characters.

Then the messages have to be parsed, so every single customer had to write an english language parser, instead of a machine to machine <escape><command><data><terminator> packet that can be used directly. Or JSON, or compact binary - anything is better than human readable - after debugging there is no human.

Next, to get reasonable throughput I run the module at 115,200 baud, but the backend processor (STM32F407) will overrun unless I use interrupts or DMA input (since it doesn't have a hardware UART FIFO like the old NS16450s). To get interrupt or DMA input running on the F4 (and others) HAL from CubeMX, you have to tell the input routines how many characters to receive or else they will hang waiting and give you a busy return if you ask for too many, or get out of sync if you ask for too few. BUT the SPWF doesn't give a byte predictable response size, therefore you have to use polled or single character interrupt input and run at a lower baud rate to avoid overrun (or rewrite the HAL to give partial results). Typically you would expect ''<cr><lf>OK<cr><lf>'' for a count of 6, but you might get an error with its own format and length, so you have to expect the longest possible packet and parse it.

Do you ask for 100 or 200 characters and hang on a timeout, then somehow clobber the interrupt and see what is left in the receive buffer? Do you bring in one character at a time until you hit the terminator (which are the first characters so you don't actually get the data, you see where this is going?)? Or do you rewrite the HAL interrupt routines?

Many questions. Basically, does ST have any flexibility in this project, or are the developers just working with what the original company sold them, expecting that someone thought about how the customer will actually use it?

4 REPLIES 4
Posted on December 18, 2014 at 08:37

Hi Andrei,

I'm quite sure that I don't understand the expected use of the SPWF01 modules. Perhaps I've been doing this stuff too long and have become a crufty old guy, but the command/response protocol seems like it's written expecting a human on the end of the serial port instead of a micro. Help me out here.

I'll try!

Here's the problem; the wifi modules have a response structure that is great for humans but a tad odd for parsing by computers. If I was to use the facilities of C for a parser, I would use something like gets() to get input up to the end of line. The module prepends cr/lf to its responses, so it looks great on hyperterm, but it terminates a gets() call before getting to any actual data. So, I have to bring in a ''whole bunch'' of data and parse it. The alternatives are to know the number of characters to expect, keep reading until you hit a terminator, or wait for a timeout.

If you expect to use C standard library functions, you'll probably have some trouble. Best way, is to implement a parser which throws away CR and LF chars.

There isn't any BNF, and there isn't any way to know how many bytes are coming from the module.

The best way to use a module like this (I think) is having an external circular buffer, and a thread which:

- empty the circular buffer, copying in a service buffer;

- parses the service buffer, looking for number of indication. Here, if you want, you can use standard library functions like sscanf ''\r\n+WIND:%d:%s\r\n'';

- call proper callback associated to  indication number found.

Okay, bring in a bunch of data and look for the terminator. The terminator comes first, then a bunch of data, then a terminator. Well, that's going to be a weird parser, do two pieces perhaps, but what if it isn't a response. AND all of this stuff is coming ''in band'' with my application data being transferred. If the module messages had some kind of ''escape sequence'' in front of them instead of cr/lf I could write a parser for that.

Again, if you expect to use C standard library functions, you'll probably have some trouble.

The messages don't have a standard length of response, so you can't just use a read X characters.

If you are using a circular buffer, you don't need to know how many bytes are coming from the module.

Then the messages have to be parsed, so every single customer had to write an english language parser, instead of a machine to machine <escape><command><data><terminator> packet that can be used directly. Or JSON, or compact binary - anything is better than human readable - after debugging there is no human.

I suggest a callback approach, like above.

Next, to get reasonable throughput I run the module at 115,200 baud, but the backend processor (STM32F407) will overrun unless I use interrupts or DMA input (since it doesn't have a hardware UART FIFO like the old NS16450s). To get interrupt or DMA input running on the F4 (and others) HAL from CubeMX, you have to tell the input routines how many characters to receive or else they will hang waiting and give you a busy return if you ask for too many, or get out of sync if you ask for too few. BUT the SPWF doesn't give a byte predictable response size, therefore you have to use polled or single character interrupt input and run at a lower baud rate to avoid overrun (or rewrite the HAL to give partial results). Typically you would expect ''<cr><lf>OK<cr><lf>'' for a count of 6, but you might get an error with its own format and length, so you have to expect the longest possible packet and parse it.

All of our testing platforms contain an STM32Fx. I suggest use DMA+interrupt. It's very simple this way!

Do you ask for 100 or 200 characters and hang on a timeout, then somehow clobber the interrupt and see what is left in the receive buffer? Do you bring in one character at a time until you hit the terminator (which are the first characters so you don't actually get the data, you see where this is going?)? Or do you rewrite the HAL interrupt routines?

Take a look at STM32 AN3109: Communication peripheral FIFO emulation with DMA and DMA timeout in STM32F10x microcontrollers. Maybe it can help you.

Many questions. Basically, does ST have any flexibility in this project, or are the developers just working with what the original company sold them, expecting that someone thought about how the customer will actually use it?

We always use customer feedbacks to improve SPWF Firmware. If/When needed.
Posted on January 13, 2015 at 05:20

Hello Geraldo,

I managed to get the DMA receive working - ALMOST. I can get my characters to transfer without any overruns or lost characters.

I have declared a buffer of 100 bytes. I set up the uart and DMA unit to transfer 100 bytes in a circular buffer arrangement. I don't bother with the half and complete interrupts and just use a timeout as you described.

I issue a command to the SPWF module (AT+S.SSIDTXT\n) and I always get back 28 bytes as a response. I wait an extra 10mS. then look at the DMA controller's NDTR register to see how many characters are left to transfer. Keeping track of this value implies how many characters were transferred recently. My oscilloscope indicates that I always look for the characters in the buffer well after the transfer is complete.

But, when receiving, the last 4 characters are either correct or are duplicated from earlier received characters. I suspect that the last device to memory transfer hasn't happened yet and the 4 characters, 32 bits of them, are still in the DMA unit, even though the NDTR register has been decremented.

Does this make any sense? If so, is there a way to force the buffer to flush?

Thanks,

Andrei

Posted on January 16, 2015 at 21:08

Apparently this is so.

By turning off DMA FIFO to put the DMA unit into Direct mode, each of the transfers is done directly to the buffer instead of being put into a buffer (which doesn't get unloaded until needed).

I now have a solution that doesn't drop or corrupt characters at 115200 baud, even in loopback.

Next, writing a parser for the wifi module.

Posted on December 29, 2014 at 18:19

Just a thought - If 115200 is overrunning the customer's processor, you can change the baud rate.  I presume the new baud rate would be 'sticky' if you do AT&W?

And I'm not sure why multiple gets() is a big problem.  Processing multiple gets() returns seems a lot easier to me than building some non-standard input methods.