[DONE] Serial port losing data when several threads are acti
Moderator: RoccoMarco
Re: Serial port losing data when several threads are active
Yes, the onewire spec requires a 4.7k pullup. I am using a 5k since thats what I had lying around.
-
trepidacious
- Posts: 58
- Joined: Mon Jan 21, 2013 3:36 pm
- Been thanked: 1 time
Re: Serial port losing data when several threads are active
I've been having a look at 1-wire using the serial driver, by adapting the code from here:
http://forum.chibios.org/phpbb/viewtopic.php?f=8&t=713
I ported that code to 2.6.1, and it works well, but I'm also having trouble using the serial driver, I've tried the same sdPut/sdGet approach, as well as chSequentialStreamWrite/Read, they both seem to hang on receiving data. sdPut/sdGet will sometimes make it through a whole transaction, and I get some reasonable looking data back, but with an incorrect CRC which makes me think something else is wrong. However if I perform a few transactions, eventually it will hang on sdGet. This is with no other threads running, with serial access from the main thread via a shell command.
I'm not completely sure how I should be using the serial driver, so I may well have something misconfigured.
My reason for using the serial driver is that I've run out of DMA streams due to the DCMI problem on STM32F407. While my 1-wire test is not using any other threads, I intend to use the 1-wire driver on another project where there is much more going on.
I can make the code available if that helps.
http://forum.chibios.org/phpbb/viewtopic.php?f=8&t=713
I ported that code to 2.6.1, and it works well, but I'm also having trouble using the serial driver, I've tried the same sdPut/sdGet approach, as well as chSequentialStreamWrite/Read, they both seem to hang on receiving data. sdPut/sdGet will sometimes make it through a whole transaction, and I get some reasonable looking data back, but with an incorrect CRC which makes me think something else is wrong. However if I perform a few transactions, eventually it will hang on sdGet. This is with no other threads running, with serial access from the main thread via a shell command.
I'm not completely sure how I should be using the serial driver, so I may well have something misconfigured.
My reason for using the serial driver is that I've run out of DMA streams due to the DCMI problem on STM32F407. While my 1-wire test is not using any other threads, I intend to use the 1-wire driver on another project where there is much more going on.
I can make the code available if that helps.
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: Serial port losing data when several threads are active
Hi,
Do you handle transmission errors and the case where some data is lost? if you wait for a fixed number of bytes and some is lost because an error then the code would wait for more data that will never be sent.
It is just an hypothesis of course, it all depends on your code. In general:
If you send/receive a fixed amount of data without delimiters you have to handle the case where the number of received bytes is different from what you expect. This can be done using timeouts for example.
It is a good idea to frame your data with delimiters, text lines for example, this way you just wait for the delimiter, regardless the lenght of the data in the frame. This makes easier to resynchronize with the data flow in case of errors.
Giovanni
Do you handle transmission errors and the case where some data is lost? if you wait for a fixed number of bytes and some is lost because an error then the code would wait for more data that will never be sent.
It is just an hypothesis of course, it all depends on your code. In general:
If you send/receive a fixed amount of data without delimiters you have to handle the case where the number of received bytes is different from what you expect. This can be done using timeouts for example.
It is a good idea to frame your data with delimiters, text lines for example, this way you just wait for the delimiter, regardless the lenght of the data in the frame. This makes easier to resynchronize with the data flow in case of errors.
Giovanni
-
trepidacious
- Posts: 58
- Joined: Mon Jan 21, 2013 3:36 pm
- Been thanked: 1 time
Re: Serial port losing data when several threads are active
Hi,
Thanks, I'm now using sdGetTimeout, and I'm seeing random timeouts, sometimes none in a transaction, usually a timeout every 10 or so bytes. The data that I DO get looks more or less right, but not quite perfect even when I get no timeouts.
For normal serial use I agree I would normally use a timeout and delimiters to allow for errors. However in this case I was expecting to know exactly what I would receive, since the UART is configured for open drain half-duplex to work with 1-wire, so it should always see its own start bits, and so always receive one byte back per byte sent (often the same byte, but the 1-wire device can pull the line low during the data bits to return data).
If I use code like:
am I guaranteed to see each transmitted byte received back again? Is there any way for the byte to be transmitted before the uart is ready to receive? I assume it is receiving as long as the serial devices is started with sdStart?
I've done some more testing with the UART driver, where I can use:
and this seems very reliable.
Thanks,
Ben.
Thanks, I'm now using sdGetTimeout, and I'm seeing random timeouts, sometimes none in a transaction, usually a timeout every 10 or so bytes. The data that I DO get looks more or less right, but not quite perfect even when I get no timeouts.
For normal serial use I agree I would normally use a timeout and delimiters to allow for errors. However in this case I was expecting to know exactly what I would receive, since the UART is configured for open drain half-duplex to work with 1-wire, so it should always see its own start bits, and so always receive one byte back per byte sent (often the same byte, but the 1-wire device can pull the line low during the data bits to return data).
If I use code like:
Code: Select all
sdPut(drv->config.uartd, *send_buf);
r = sdGetTimeout(drv->config.uartd, MS2ST(10));
am I guaranteed to see each transmitted byte received back again? Is there any way for the byte to be transmitted before the uart is ready to receive? I assume it is receiving as long as the serial devices is started with sdStart?
I've done some more testing with the UART driver, where I can use:
Code: Select all
uartStartReceive(drv->config.uartd, len , receive_buf);
uartStartSend(drv->config.uartd, len, send_buf);
and this seems very reliable.
Thanks,
Ben.
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: Serial port losing data when several threads are active
Hi,
Do you listen for errors using an event? it would be useful to know if you are getting framing or parity errors too. Timeouts could be just a consequence of errors in the stream.
Giovanni
Do you listen for errors using an event? it would be useful to know if you are getting framing or parity errors too. Timeouts could be just a consequence of errors in the stream.
Giovanni
-
trepidacious
- Posts: 58
- Joined: Mon Jan 21, 2013 3:36 pm
- Been thanked: 1 time
Re: Serial port losing data when several threads are active
Hi,
I've added an event listener for the errors, looks like all I get is an SD_NOISE_ERROR when doing the "one wire reset" part of the comms. I guess this is because the one-wire devices pull the line low at an unexpected time, however they should always set at least one bit low, so I think this can be ignored.
I did find one definite error in my code - with the uart driver, it's easy to ignore received data by just using uartStartSend with no preceding uartStartReceive. When I adapted this, I forgot to make sure to clear this received data with sdGet, when performing a send rather than a transfer. Fixing this seems to fix everything, although I'm really not sure how I was getting timeouts before. I don't seem to be getting them now, but they went away BEFORE I fixed the code, so this might be a signal problem still. At least I can watch out for any errors with events and timeouts, thanks for the help debugging!
Ben.
I've added an event listener for the errors, looks like all I get is an SD_NOISE_ERROR when doing the "one wire reset" part of the comms. I guess this is because the one-wire devices pull the line low at an unexpected time, however they should always set at least one bit low, so I think this can be ignored.
I did find one definite error in my code - with the uart driver, it's easy to ignore received data by just using uartStartSend with no preceding uartStartReceive. When I adapted this, I forgot to make sure to clear this received data with sdGet, when performing a send rather than a transfer. Fixing this seems to fix everything, although I'm really not sure how I was getting timeouts before. I don't seem to be getting them now, but they went away BEFORE I fixed the code, so this might be a signal problem still. At least I can watch out for any errors with events and timeouts, thanks for the help debugging!
Ben.
-
trepidacious
- Posts: 58
- Joined: Mon Jan 21, 2013 3:36 pm
- Been thanked: 1 time
Re: Serial port losing data when several threads are active
I don't know whether this is the real cause of the problems, but I've worked out what changed to get rid of the timeouts - if I have an event listener registered on the serial driver, and I call chEvtWaitOneTimeout on it in a loop, I get reliable comms. If I don't run the thread with that loop, I get many timeouts. If I make that thread just loop with a 10ms sleep, I still get the timeouts. It doesn't seem to be necessary to even "get" the flags - previously I was using chEvtGetAndClearFlags and then printing any errors to USB serial, but I've removed that and comms still run fine.
Is it mandatory to use the event listener for comms to work, or is this just a symptom of some other bug in my code I've not found yet?
Is it mandatory to use the event listener for comms to work, or is this just a symptom of some other bug in my code I've not found yet?
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: Serial port losing data when several threads are active
It is not mandatory if you are not interested in errors. I think there is something in the code
do you implement a state machine for your protocol? if so, is it correctly implemented?
Giovanni
Giovanni
-
trepidacious
- Posts: 58
- Joined: Mon Jan 21, 2013 3:36 pm
- Been thanked: 1 time
Re: Serial port losing data when several threads are active
The protocol is quite simple, so no state machine is needed to give a synchronous interface to 1-wire devices. Each transaction with a 1-wire device just consists of a series of bytes sent by the MCU in half duplex mode, so that the MCU receives back every byte it sends. If the 1-wire device is expected to be "sending" data then the byte received by the MCU is checked against the byte it sent, and any changes are due to the 1-wire device pulling the half-duplex line low during the byte. Everything is driven by the MCU, so there's no need to respond to comms initiated by the device, so I don't really need events at all (except to check for errors, which I'm not seeing any more after enabling one-bit mode to ignore noise errors).
Just in case there is anything obvious (or anyone wants to use the code), here's a zip of the project https://www.dropbox.com/s/jf5q7vakvb7ket3/discovery-serial-1wire.tar.gz - it's basically just the same code from this thread http://forum.chibios.org/phpbb/viewtopic.php?f=8&t=713 but with an added driver for the MAX31826, and a define to switch from UART driver to serial driver (currently set to true). The only interesting code is in oneWire.c/h, in the transfer() and send() functions, which just call sdPut() and sdGetTimeout(), and in main.c in the serial_event_thread() function. If that thread is started, everything works fine, otherwise serial comms time out. It should all work fine on a discovery board with nothing connected except a 5K pullup on PD8, running "ow maxsingle" will try to talk to a 1-wire device, this will cause a large number of timeouts if the event listener is not running. If the event listener is running, the serial communications will work fine (obviously the transaction as a whole will fail - the shell will print a message about a bad CRC since there was no device to actually send back data).
Just in case there is anything obvious (or anyone wants to use the code), here's a zip of the project https://www.dropbox.com/s/jf5q7vakvb7ket3/discovery-serial-1wire.tar.gz - it's basically just the same code from this thread http://forum.chibios.org/phpbb/viewtopic.php?f=8&t=713 but with an added driver for the MAX31826, and a define to switch from UART driver to serial driver (currently set to true). The only interesting code is in oneWire.c/h, in the transfer() and send() functions, which just call sdPut() and sdGetTimeout(), and in main.c in the serial_event_thread() function. If that thread is started, everything works fine, otherwise serial comms time out. It should all work fine on a discovery board with nothing connected except a 5K pullup on PD8, running "ow maxsingle" will try to talk to a 1-wire device, this will cause a large number of timeouts if the event listener is not running. If the event listener is running, the serial communications will work fine (obviously the transaction as a whole will fail - the shell will print a message about a bad CRC since there was no device to actually send back data).
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: Serial port losing data when several threads are active
Have you considered the use of the UART driver instead? being based on callbacks would make the implementation of a state machine easier, virtual timers could be used for timeouts if you need them.
Giovanni
Giovanni