0
Offline
Newbie
Karma: 0
Posts: 12
Arduino rocks
|
 |
« Reply #30 on: January 02, 2012, 06:00:15 am » |
I'm having some buffer overflow problems with the 23 code and when I saw the configurable buffer size I setup the 1.0 code base on a windows 7/64 machine. The 64 byte buffer is way too small when I get back to back messages while writing to the SD card as you have noted in other replies. So to use this alternative library, I copy the folder SerialPort to the arduino-1.0/libraries folder, if I interpret the readme.txt correctly. It is a tad unclear where it seems to have dropped something expected after 'to the' and continues on next line with 'your libraries directory.' I am not sure how this will replace the core coding or override the core coding. Please direct me or hint/link to what I am missing.
quote: " This library provides access to the Arduino serial ports.
To install the this library, copy the SerialPort folder to the your libraries directory.
If you only use unbuffered TX, edit SerialPort.h and set BUFFERED_TX zero." endquote:
|
|
|
|
|
Logged
|
|
|
|
|
Guildford, UK
Offline
Full Member
Karma: 0
Posts: 217
Arduino rocks
|
 |
« Reply #31 on: January 02, 2012, 07:27:21 am » |
The core Arduino based serial port code is only included in your sketch if you actually use it. For example: void setup() { Serial.begin(9600); Serial.println("Using Arduino supplied HardwareSerial"); }
void loop() { }
So if you've copied the SerialPort folder from the zip file into your Libraries folder (So you have Arduino-1.0\libraries\SerialPort\SerialPort.h and Arduino-1.0\libraries\SerialPort\SerialPort.cpp) you can write the following code instead #include <SerialPort.h>
SerialPort<0, 32, 256> port;
void setup() { port.begin(9600); port.println("Using SerialPort class"); }
void loop() { }
Just remember to do the following and you should be alright: - Include <SerialPort.h>
- Declare new Serial port including its parameters
- Initialise (call begin()) and use the new serial port (NOT Serial)
The configuration of the serial port looks odd to anyone not familiar with C++ templates, but it's easy to explain. The first parameter inside the angle brackets is the serial port number. Unless you've got a board with more than one serial port (e.g. Arduino Mega) this will always be 0. The second parameter is the size of the receive buffer in bytes and the third is the size of the transmit buffer in bytes. You can ignore the stuff about editing SerialPort.h. You'll only need this is you're short of flash memory at which point you can come back and ask more questions. If you do by chance refer to both the new SerialPort and HardwareSerial in the same sketch you'll get some error messages about duplicate interrupt vectors. Hope that helps. Iain
|
|
|
|
|
Logged
|
|
|
|
|
Smithfield, Rhode Island
Offline
God Member
Karma: 2
Posts: 828
|
 |
« Reply #32 on: January 02, 2012, 09:23:38 pm » |
This looks really cool, I'll give it a try this week. By coincidence, I'm working on a project that uses three serial ports, at different baud rates. So I need a big buffer on some and not on others. I'm one of those people that could put a buffer bigger than 256 bytes to use.
Also, on the 9 bit support, its really handy for those who work with RS-485 busses. Not that I'm asking you to add it here, I just wanted to address the comment that its never needed.
Thanks very much!
|
|
|
|
|
Logged
|
|
|
|
|
North Queensland, Australia
Offline
Edison Member
Karma: 35
Posts: 1279
|
 |
« Reply #33 on: January 02, 2012, 09:40:55 pm » |
I'm not sure how this will fair with multiple instances of a class but, If people do not want 16bits for storage this may help. This change should be fine as the non-type template is specific to each specification of SerialPort, however this may lead to an increase of code with multiple instances. struct SerialRingBuffer { uint8_t* buf; /**< Pointer to start of buffer. */ uint16_t head; /**< Index to next empty location. */ uint16_t tail; /**< Index to last entry if head != tail. */ uint16_t size; /**< Size of the buffer. Capacity is size -1. */ }; changed to template< const int _MaxSize > struct SerialRingBuffer { uint8_t* buf; /**< Pointer to start of buffer. */ #if ( _MaxSize > 255 ) uint16_t head; /**< Index to next empty location. */ uint16_t tail; /**< Index to last entry if head != tail. */ uint16_t size; /**< Size of the buffer. Capacity is size -1. */ #else uint8_t head; /**< Index to next empty location. */ uint8_t tail; /**< Index to last entry if head != tail. */ uint8_t size; /**< Size of the buffer. Capacity is size -1. */ #endif };
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 12
Arduino rocks
|
 |
« Reply #34 on: January 02, 2012, 09:51:34 pm » |
Thank you very much and your examples help answer a number of questions. On the Mega1280 I am able to compile and use the SerialPort alternate library examples but when I include the SD library I'm getting some problems. Just adding #include <SD.h> brings up vector conflicts in the core HardwareSerial code so I will have to do some more digging for details. #include <SerialPort.h> #include <SD.h>
SerialPort<0, 32, 256> port;
void setup() { port.begin(9600); port.println("Using SerialPort class"); }
void loop() { }
When the SD.h is compiled here are the compiler errors I'm getting. core.a(HardwareSerial.cpp.o): In function `__vector_25': C:\Arduino\arduino-1.0\hardware\arduino\cores\arduino/HardwareSerial.cpp:102: multiple definition of `__vector_25' SerialPort\SerialPort.cpp.o:C:\Arduino\arduino-1.0\libraries\SerialPort/SerialPort.cpp:37: first defined here core.a(HardwareSerial.cpp.o): In function `__vector_36': C:\Arduino\arduino-1.0\hardware\arduino\cores\arduino/HardwareSerial.cpp:127: multiple definition of `__vector_36' SerialPort\SerialPort.cpp.o:C:\Arduino\arduino-1.0\libraries\SerialPort/SerialPort.cpp:57: first defined here core.a(HardwareSerial.cpp.o): In function `__vector_51': C:\Arduino\arduino-1.0\hardware\arduino\cores\arduino/HardwareSerial.cpp:140: multiple definition of `__vector_51' SerialPort\SerialPort.cpp.o:C:\Arduino\arduino-1.0\libraries\SerialPort/SerialPort.cpp:64: first defined here core.a(HardwareSerial.cpp.o): In function `__vector_54': C:\Arduino\arduino-1.0\hardware\arduino\cores\arduino/HardwareSerial.cpp:153: multiple definition of `__vector_54' SerialPort\SerialPort.cpp.o:C:\Arduino\arduino-1.0\libraries\SerialPort/SerialPort.cpp:71: first defined here core.a(HardwareSerial.cpp.o): In function `__vector_26': C:\Arduino\arduino-1.0\hardware\arduino\cores\arduino/HardwareSerial.cpp:190: multiple definition of `__vector_26' SerialPort\SerialPort.cpp.o:C:\Arduino\arduino-1.0\libraries\SerialPort/SerialPort.cpp:95: first defined here core.a(HardwareSerial.cpp.o): In function `__vector_37': C:\Arduino\arduino-1.0\hardware\arduino\cores\arduino/HardwareSerial.cpp:221: multiple definition of `__vector_37' SerialPort\SerialPort.cpp.o:C:\Arduino\arduino-1.0\libraries\SerialPort/SerialPort.cpp:111: first defined here core.a(HardwareSerial.cpp.o): In function `__vector_52': C:\Arduino\arduino-1.0\hardware\arduino\cores\arduino/HardwareSerial.cpp:238: multiple definition of `__vector_52' SerialPort\SerialPort.cpp.o:C:\Arduino\arduino-1.0\libraries\SerialPort/SerialPort.cpp:118: first defined here core.a(HardwareSerial.cpp.o): In function `__vector_55': C:\Arduino\arduino-1.0\hardware\arduino\cores\arduino/HardwareSerial.cpp:255: multiple definition of `__vector_55' SerialPort\SerialPort.cpp.o:C:\Arduino\arduino-1.0\libraries\SerialPort/SerialPort.cpp:125: first defined here
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 12
Arduino rocks
|
 |
« Reply #35 on: January 02, 2012, 10:07:24 pm » |
Ok that didn't take long to find after all. SD.h includes Arduino.h and Arduino.h includes HardwareSerial.h
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Edison Member
Karma: 30
Posts: 1105
Arduino rocks
|
 |
« Reply #36 on: January 02, 2012, 10:11:47 pm » |
SD.h accesses Serial so it can't be used with SerialPort. Serial uses the same interrupt vector as SerialPort.
I plan to modify SdFat so it can be used with SerialPort.
The problem is use of Serial, not the include of Arduino.h. SerialPort includes Arduino.h.
|
|
|
|
« Last Edit: January 02, 2012, 10:35:12 pm by fat16lib »
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 12
Arduino rocks
|
 |
« Reply #37 on: January 02, 2012, 11:21:08 pm » |
Thanks for the information and plans for SDFat modification but I feel like I'm creating more work and wish to be helping more. Guess it's time to learn more about the workings of SD and it's interaction with serial.
|
|
|
|
|
Logged
|
|
|
|
|
SF Bay Area (USA)
Offline
Faraday Member
Karma: 80
Posts: 5513
Strongly opinionated, but not official!
|
 |
« Reply #38 on: January 03, 2012, 05:35:23 am » |
You can probably speed up serial write() quite a bit if you're willing to require that the buffer size be a power of two. Right now it's calling a 16bit divide function for each byte...
|
|
|
|
|
Logged
|
|
|
|
|
Guildford, UK
Offline
Full Member
Karma: 0
Posts: 217
Arduino rocks
|
 |
« Reply #39 on: January 03, 2012, 05:46:06 am » |
That sounds like a reasonable limitation. I've only used powers of 2 so far. And you can enforce this easily using the pre-processor.
Iain
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Edison Member
Karma: 30
Posts: 1105
Arduino rocks
|
 |
« Reply #40 on: January 03, 2012, 08:51:09 am » |
There is no point in limiting buffers to a power of two. You don't need a divide to maintain the index for a ring buffer. A power of two is very coarse for large buffers on a 328. 512 vs 1024 for example. Also these functions are small and fast so I don't see a point in limiting the ring buffer indices to 8-bits. Here are my get and put functions for the next version of SerialPort: //------------------------------------------------------------------------------ /** get the next byte * \param[in] b location for the returned byte * \return true if a byte was returned or false if the ring buffer is empty */ bool SerialRingBuffer::get(uint8_t* b) { size_t t = tail; if (head == t) return false; *b = buf[t++]; tail = t < size ? t : 0; return true; } //------------------------------------------------------------------------------ /** put a byte into the ring buffer * \param[in] b the byte * \return true if byte was transfered or false if the ring buffer is full */ bool SerialRingBuffer::put(uint8_t b) { size_t h = head; // OK to store here even if ring is full buf[h++] = b; if (h >= size) h = 0; if (h == tail) return false; head = h; return true; }
|
|
|
|
|
Logged
|
|
|
|
|
Guildford, UK
Offline
Full Member
Karma: 0
Posts: 217
Arduino rocks
|
 |
« Reply #41 on: January 03, 2012, 09:01:52 am » |
There is no point in limiting buffers to a power of two. You don't need a divide to maintain the index for a ring buffer.
Fair enough. If there's no reason for it, don't bother. I seen to remember the old HardwareSerial did do divides but my memory might be failing me. Iain
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Edison Member
Karma: 30
Posts: 1105
Arduino rocks
|
 |
« Reply #42 on: January 03, 2012, 09:24:28 am » |
For faster writes, it is better to optimize multibyte writes. I have been able to make the time to buffer data for write(const char*) and write(uint8_t*, size_t ) about 15 time faster than HardwareSerial. See this post http://arduino.cc/forum/index.php/topic,85462.0.htmlThe example in the above post compares times for this statement to execute: Serial.write("lkjljlkjlkjljlkjlkjlkjlkjlkjlkjlkj"); The time is over 900 us for HardwareSerial and about 60 us for SerialPort. I will soon post this version of SerialPort. I have also added options for parity, character size, number of stop bits, and RX error checking. I return four types of RX errors, framing, parity, USART overrun, and ring buffer overflow.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Edison Member
Karma: 30
Posts: 1105
Arduino rocks
|
 |
« Reply #43 on: January 03, 2012, 12:15:42 pm » |
I posted a new beta, SerialPortBeta20120103.zip, here http://code.google.com/p/beta-lib/downloads/listHere is the changes.txt file: 3 Jan 2012
Almost total rewrite so expect bugs! Be sure to tell me about bugs.
See html for more details about the following functions.
Changed begin() to have a optional second argument to set parity, character size, and number of stop bits.
void begin (long baud, uint8_t options = SP_8_BIT_CHAR)
The following can be ORed together for options:
Choose one stop bit option. static const uint8_t SP_1_STOP_BIT = 0 (default) static const uint8_t SP_2_STOP_BIT = M_USBS
Choose one character size. static const uint8_t SP_5_BIT_CHAR = 0 static const uint8_t SP_6_BIT_CHAR = M_UCSZ0 static const uint8_t SP_7_BIT_CHAR = M_UCSZ1 static const uint8_t SP_8_BIT_CHAR = M_UCSZ0 | M_UCSZ1
Choose one parity option. static const uint8_t SP_EVEN_PARITY = M_UPM1 static const uint8_t SP_NO_PARITY = 0 static const uint8_t SP_ODD_PARITY = M_UPM0 | M_UPM1
Added RX error checking.
The following error bits are returned: static const uint8_t SP_FRAMING_ERROR = M_FE static const uint8_t SP_PARITY_ERROR = M_UPE static const uint8_t SP_RX_BUF_OVERRUN = 1 static const uint8_t SP_RX_DATA_OVERRUN = M_DOR
Added the following functions:
void clearRxError() uint8_t getRxError() size_t read (uint8_t *b, size_t n) size_t write (const char *s) - overrides version in Stream size_t write (uint8_t *b, size_t n) - overrides version in Stream size_t writeln (const char *s) size_t writeln ()
|
|
|
|
|
Logged
|
|
|
|
|
Guildford, UK
Offline
Full Member
Karma: 0
Posts: 217
Arduino rocks
|
 |
« Reply #44 on: January 03, 2012, 04:00:29 pm » |
I've tried it out and it is faster when using RAM strings, but to save space most of my debug messages are coming from flash memory. Could I request 1 additional function that takes a __FlashStringHelper as an argument can copies it directly into the ring buffer? At present I'm copying from __FlashStringHelper to a RAM buffer and then passing on to SerialPort. Still faster than before but could be faster still. Not seen any bugs yet. Iain
|
|
|
|
|
Logged
|
|
|
|
|
|