Show Posts
Pages: [1] 2 3 4
1  Forum 2005-2010 (read only) / Bugs & Suggestions / Add error checking to hardware serial library on: February 01, 2009, 10:50:58 pm
I am working on some extensions to the serial library (error handling, set parity and word length).   Currently I think I am going to have to copy and rename every function in wiring_serial into a new library.   I have this working as a hack to wiring_serial, but I cant find an better way to do this.
FYI - as far as I can tell you cant simply read the UDR0 register from loop because it is cleared as the UART receives each new character.  It has to be read before the character is read.

Two questions:
1) please confirm that there is no way to "chain" an existing interrupt handler.  It looks like the compiler will only allow one ISR to a given interrupt.  When I say one ISR, I mean define the first ISR, grab a pointer to it, then re-define it with an second ISR which calls the original routine with a function pointer.   (standard interrupt chaining)  I was going to try this in inline assemler when I realized the interrupt vectors are stored in flash and could only be modified at great risk.  Basically, this is a useful capability, but the best way to get there seems to be to edit wiring_serial.  Anything else is even uglier -- creating a copy of wiring_serial with all different names etc.....

2) I would like to seriously propose the following mod to wiring_serial, this adds a couple of instructions and one byte variable, but it allows reasonable error checking on serial reads.  Basically the error byte is ORed until it is used so it indicates any errors for a group of serial reads.   Much faster than checking for errors after each read.

more info here or I can repost
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1232301240

Proposed changes
Code:
// this stuff is near the top of the files
int rx_buffer_head = 0;
int rx_buffer_tail = 0;
//  ********begining of first change*******
// new status variable here
byte status_reg = 0;

//function to return status byte
//status variable reset to 0 with each call
int serialStatus(void)
{
  int temp;
  temp = status_reg;
  status_reg = 0;
  return temp;
}
//  ******end of  first change*********
void beginSerial(long baud)

//**** second change ***********
//  skip further down the file to make this change
//  modify the interrupt/signal routine
// ****************************
#if defined(__AVR_ATmega168__)
SIGNAL(SIG_USART_RECV)
#else
SIGNAL(SIG_UART_RECV)
#endif
{
#if defined(__AVR_ATmega168__)
      unsigned char c = UDR0;
#else
      unsigned char c = UDR;
#endif
// ************ begin second change *********
//get status byte
               status_reg = status_reg | UCSR0A;
//************  end second change  **********
      int i = (rx_buffer_head + 1) % RX_BUFFER_SIZE;

      // if we should be storing the received character into the location
      // just before the tail (meaning that the head would advance to the
      // current location of the tail), we're about to overflow the buffer
      // and so we don't write the character or advance the head.
      if (i != rx_buffer_tail) {
            rx_buffer[rx_buffer_head] = c;
            rx_buffer_head = i;
      }
}

 
2  Forum 2005-2010 (read only) / Bugs & Suggestions / Re: Serial error checking on: January 24, 2009, 10:58:01 pm
The hack as given is just to check for receive errors.
But it shouldnt be hard to set 7/even parity.  
(typing this in for the second time arrgh.)
Note: I havent tested this and I can be a bit dyslexic on bit order.  Please check the datasheet yourself.  You may also want to look at "wiring_serial" to see how the syntax looks.

1) check page 192-194 of the AVR168 datasheet for the USART registers.
http://www.atmel.com/dyn/resources/prod_documents/doc2545.pdf

2) Use serial.begin(9600); to set baud rate and set up interrupt handler/buffering.

3) set word length to 7  
USCR0B = UCSR0B & B11111011;
UCSR0C = UCSR0C | B00000010;
UCSR0C = UCSR0C & B11111110;

4) set parity to even
UCSR0C = UCSR0C | B00100000;
UCSR0C = UCSR0C & B11101111;

5) use the serial.read and serial.print functions as normal.

This works because the USART registers are written to once by serial.begin.  Once that is set up you can change most of the parameters yourself.  I used this same trick with MS-DOS to set nonstandard baud rates.
3  Forum 2005-2010 (read only) / Bugs & Suggestions / Serial error checking on: January 22, 2009, 11:06:30 pm
I just hacked wiring_serial.c and wiring.h so I could return the value of the UCSR0A register.  I can now receive any number of serial bytes, then check to see if there were any hardware receive errors.   This works for testing, but obviously hacking wiring isnt the right way to do this for "production" code.  

Here is the thread in "hardware interfacing" where posted this hack
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1232301240

Questions:
1) This is quite small (one variable, one assignment statement), should I suggest this as a wiring improvement.

2) I would like to create a "test_serial" library that is an exact copy of wiring_serial.c except with my hack.  I assume if you only used functions from the test _serial library there would be no conflict with wiring_serial.   However -- when I simply rename and recompile wiring_serial.c I get compile errors.  Any hints on how to easily clone an existing library.

finally if I can get a "test_serial" library running there are some other troubleshooting functions that could be added like "autobaud", possibly an error rate test, even/odd parity etc.  Not stuff that would go in the core, but perhaps useful with old equipment.
4  Forum 2005-2010 (read only) / Syntax & Programs / Re: using internal pullup resistors on: January 29, 2009, 09:49:44 pm
This is the schematic for LadyAda's Boarduino, but the pin references are the same.

http://www.ladyada.net/media/boarduino/usbboarduinosch.png
5  Forum 2005-2010 (read only) / Syntax & Programs / Re: Sine wave led fade in and out on: January 28, 2009, 09:30:47 pm
Not sure if you want a sine wave specifically or just a nice looking fade in fade out on the LED.

Something that makes a convincing LED fade is a fibonacci sequence of delays.  1 2 3 5 8 13 21 etc.  Then multiply by your minimum delay when you build your table.

As the LED gets brighter you need a larget step to make a detectible difference anyway.  The Fibonacci sequence acts a lot like a log scale, but it is much faster to compute your table.  I suspect a sine is going to seem like full bright 1/3 of the time and full dark 1/3 of the time....
6  Forum 2005-2010 (read only) / Syntax & Programs / Re: When to use a .C library vs a .CPP library on: January 24, 2009, 12:28:00 pm
Thanks - thats just what I needed.  I didnt understand th C header.
7  Forum 2005-2010 (read only) / Syntax & Programs / When to use a .C library vs a .CPP library on: January 23, 2009, 09:15:24 pm
I am copying the wiring_serial library for testing.  I want to create a new "test_serial" with my mods.  Hopefully that avoids the risks of continuing to edit the core code.  

My question is, HardwareSerial.cpp appears to simply call "wiring.serial.c"  presumably to put a C++ face on it.   Is there any reason I cannot make my new library a .CPP to start with?  It looks like you can hook interrupts in .CPP.   Or for that matter is there any problem with creating a .C library and distributing it?
8  Forum 2005-2010 (read only) / Syntax & Programs / Re: Generating 2 different frequencies only on timer 1 on: January 23, 2009, 09:59:21 pm
I havent messed with the compare registers on the AVR, but I have on the TI MSP430.  So- looking at the datasheet I think it works the same way.   You can get two different frequencies if you can handle the interrupts fast enough.  The neat thing is that you can get any increment of the timer frequency.

If you put two fixed values in the output compare registers, they will just interrupt at a fixed offset of a the timer period.  The trick is to put an updated value in the compare register every time it fires.

Set the timer to run continuously and just let it overflow.  Set your first two delays in your two compare registers.

When the first compare happens, your interrupt routine needs to add your interval to the compare value and update the compare register.  Likewise when the second compare matches, add its (longer or shorter) interval and update it.

The magic is that you just add a 16 bit value to your old compare value and IGNORE THE OVERFLOW.  Your math will overflow (wrap around) exactly like the timer.    Also, you have a fairly long time to update the registers because you just have to have the new value stuffed before the timer gets there.

That said - you need a fast interrupt handler, and you need to determine which compare triggered the interrupt.  You can do this in C, but you will probably have to set the hardware registers directly.  Also your maximum frequency is limited by the number of instructions in your interrupt handler.   I was doing servos, so there was always plenty of time.

This project doesnt do two frequencies, but it does mess with the same registers....
http://www.evilmadscientist.com/article.php?story=avrdac
9  Forum 2005-2010 (read only) / Syntax & Programs / Re: Buffer and serial input on: January 23, 2009, 09:28:09 pm
Since this is a human interface you dont have to always enter 3 characters or use a termination char.  You can also wait until you have not received any input for a second (or half sec.).    

If the user enters more than 2-3 chars, you decide whether to keep the first 3 or the last 3 entered.   Or you could decide more than 3 chars signals a mistake and ignore all input until there is a 1 sec pause.

Think about setting time on a digital clock.  
10  Forum 2005-2010 (read only) / Interfacing / Re: Faster Serial Communication? on: February 01, 2009, 09:49:48 pm
You should be able to send somewhere between close to 3K   characters a second with the serial (unless there is software overhead I am missing).   However digitalRead has some error checking and has a significant delay.  As I recall,  it is around 1/60 of a second.

If digitalRead/Write are slowing you down you can read/write directly to the port close to 4million times a second.  Look up "port manipulation".  There are several forum posts on the subject.  The serialWrite code is pretty tight and I doubt you could do it any faster than the library.
11  Forum 2005-2010 (read only) / Interfacing / Re: Arduino and tachometer from 12V car battery gen on: January 29, 2009, 09:23:22 pm
FYI GrumpyMike just provided this in another post
input protecton
http://www.thebox.myzen.co.uk/Tutorial/Protection.html
12  Forum 2005-2010 (read only) / Interfacing / Re: Arduino and tachometer from 12V car battery gen on: January 27, 2009, 10:39:23 pm
For some reason on I feel silly using the word "zener" in two posts on the same day...

I am sure there is a yet better way to protect the Arduino, but a 5 volt zener with the anode  (unstriped positive end)  to ground is probably the minimum.  Any thing over 5 volts gets shunted to ground.

zener zener zener smiley-razz

13  Forum 2005-2010 (read only) / Interfacing / Re: PWM H-Bridge circuit on: August 09, 2009, 09:29:30 pm
I am pretty sure the power window motors I have seen for sale have been described as "limited duty cycle".  A reduced duty cycle would also reduce your transistor heating...  
14  Forum 2005-2010 (read only) / Interfacing / Re: Setting Serial Data, Parity and Stop bits. on: June 16, 2009, 06:52:43 pm
glad it worked

I still want to get the library fixed because it covers all the parameters at once.  I would hope that would be easier in the long run.....  Also dont be afraid to go straight to the AVR datasheet for stuff like this.  It is usually pretty clear which registers to mess with and you can look at the wiring code to figure out the syntax.
15  Forum 2005-2010 (read only) / Interfacing / Re: Setting Serial Data, Parity and Stop bits. on: June 14, 2009, 08:06:33 pm
The stop bits code I posted is wrong anyway.......

Quick and dirty just
1) set baud rate with the usual command
2) add the following to your setup code:
UCSR0C = UCSR0C | B00001000;

I am pretty sure UCSR0C is predefined (note that is a ZERO not an O).
Word length is also UCSR0C (except for 9 bit).

I double checked with the AVR datasheet and the code I posted doesnt set stop bits right anyway.  Pretty embarrasing. Between the compile errors and that I am going to go retest.
Pages: [1] 2 3 4