Time ago I wanted to provide a kind of wired remote control for a device provided with a RS-232 port. So I started writing some lines in the Arduino IDE. After I wrote several functions I wanted to setup the serial port and it was an Epic Fail realize that my device only accepts 7-bit data format. Arduino it’s pre-configured with 8-n-1 frame serial format. That is 8-bit data, No-parity bit used and 1-bit for stop signaling.

How can I setup my Arduino to provide communications different from 8-n-1? My intention in this post is find out the right answer for that question.

Let’s take a look to this lines and think about what the program does:

void setup(){
  //Configure a baud rate for serial port
  Serial.begin(9600);
  delay(1000);
  //Print out the value of the serial port configuration registers
  Serial.println("Serial Ports Registers");
  Serial.println("----------------------");
  Serial.print("UCSR0A: ");
  Serial.println(UCSR0A,BIN);
  Serial.print("UCSR0B: ");
  Serial.println(UCSR0B,BIN);
  Serial.print("UCSR0C: ");
  Serial.println(UCSR0C,BIN);
  Serial.print("UBRR0H: ");
  Serial.println(UBRR0H,BIN);
  Serial.print("UBRR0L: ");
  Serial.println(UBRR0L,BIN);
}

void loop(){
}

The program is configuring the speed of Serial Port and the its only printing the value of a collection of strange labeled variables: UCSR0A, UCSR0B, UCSR0C, UBRR0H and UBRR0L. But wait!! There’s no declaration of the variables in any part of the program!

Don’t worry: This job is already done for you.

All this names (UCSR0A, UCSR0B, UCSR0C, UBRR0H and UBRR0L) are AVR registers that  allows you changing the setup. In fact when in a program you find the line Serial.begin(9600); this line is doing the dirty job of change the value from UBRR0H and UBRR0L to set the baud rate to 9600, and enabling the serial port in UCSR0A register (and, maybe, something more).

A quick view to USART Registers

OK. But, let’s take a look at the output of the former program. These lines show what we get in the serial monitor:

Serial Ports Registers
———————-
UCSR0A: 10
UCSR0B: 10011000
UCSR0C: 110
UBRR0H: 0
UBRR0L: 11001111

To get a complete understanding about what’s shown here, reading the official documentation is a must. You can find it here, at ATMEL site. But I’ll give a quick view from the information. You can follow the information from page 201 of Atmel’s documentation.

UCSR0A:

There’s only one bit active. This bit (Bit 1) is U2X0 is used to provide a double speed in the USART.

The use of rest of the bits, that aren’t set,  are for signaling different error conditions, reception and transmission complete, the data register is empty and to set a Multi Processor Communication Mode.

UCSR0B:

The status of this register shows that Reception Complete Interruption is enabled (RXCIE0: Bit 7). Also that RX and TX has been enabled (RXEN0: Bit 4 and TXEN0: Bit 3).

UCSR0C:

In this register, the bits 7 and 6 (UMSEL01:0) are used to set the Mode of communication. As we get 00 the mode selected is Async. USART.

The bits 5 and 4 (UPM01:0) are used to set the parity behavior. As these are 00 the parity check is disabled.

The bit 3 (USBS0) set to one gives you 2-Stop bit signaling. Otherwise, (with a zero value) the communication es 1-bit stop ended.

Bit 2 and 1 (UCSZ01:0) of this register, together with bit 2 (UCSZ02) in UCSR0B sets the  number of Data bits. In that case, 8 Data bit are selected.

The Bit 0 set’s the Clock polarity for the USART.

UBRR0H / UBRR0L:

This is a 16-bit long register divided in two high and low Byte register. Together configures the baud rate speed in USART. Also the U2X0 must be taken in account as well as the clock.  Check the chapter 20.10 “Examples of Baud Rate Setting” for further information.

Modifying USART Registers

I made a reading of AVR Registers but, Is it possible to set it up? Can I configure a communication pattern 7-E-2 (7-Data bit, Parity Even, 2-Stop Bits) in my Arduino UNO? Let’s try it!

With just adding a line in the former program I get the following code:

void setup(){
 //Configure a baud rate for serial port
 Serial.begin(9600);
 UCSR0C=B00011100;

delay(1000);
 //Print out the value of the serial port configuration registers
 Serial.println("Serial Ports Registers");
 Serial.println("----------------------");
 Serial.print("UCSR0A: ");
 Serial.println(UCSR0A,BIN);
 Serial.print("UCSR0B: ");
 Serial.println(UCSR0B,BIN);
 Serial.print("UCSR0C: ");
 Serial.println(UCSR0C,BIN);
 Serial.print("UBRR0H: ");
 Serial.println(UBRR0H,BIN);
 Serial.print("UBRR0L: ");
 Serial.println(UBRR0L,BIN);
 }

void loop(){
 }

Take a look that I’m still using the Serial.begin(9600); instruction instead of modify the UBRR0H and UBRR0L registers. Why? Because is easier! Of course is possible to modify UBRR0H and UBRR0L registers, and after that you must to Enable RX and TX and be sure that value in UBRR0 registers matches with the U2X0 bit or set it up for the desired speed…. Too much job.

The added line is:

UCSR0C=B00011100;

With this line the UCSR0C is set up, int the following way:

  • Asynchronous Mode USART
  • Parity Even
  • 2-Stop bits
  • 7-Data bits
  • Clock Polarity: TX-Rising, RX-Falling

To check that modifications are done properly we cannot use the Arduino Serial Monitor because all the communication parameters are fixed to 8-n-1. I checked the serial communication with moserial software, configuring the parameters according the changes made in Arduino UCSR0C register. The result is :

Serial Ports Registers
———————-
UCSR0A: 10
UCSR0B: 10011000
UCSR0C: 11100
UBRR0H: 0
UBRR0L: 11001111

Communication is done! Just modifying the AVR registers in a direct way.

Funny and Nasty things Playing with other Registers

Next Step: Is it possible to go further Accessing AVR Registers directly? Let’s try to answer this question.

Take a look at the following code:

void setup(){
  //Configure a baud rate for serial port
  Serial.begin(9600);

  delay(1000);
  //Print out the value of the MCU Control register
  Serial.println("MCU Control Registers");
  Serial.println("----------------------");
  Serial.print("MCUCR: ");
  Serial.println(MCUCR,BIN);

  delay(2000);

  MCUCR=MCUCR | B00010000;

  Serial.println();
  Serial.println("MCU Control Registers");
  Serial.println("----------------------");
  Serial.print("MCUCR: ");
  Serial.println(MCUCR,BIN);
}

void loop(){
}

This program configures first serial port in a standard way. After that shows the content of MCU Control Register. This registers provides an interesting bit: PUD: Bit 4. This one enables and disables the main internal pull-ups on digital inputs, providing a way to connect a switch without using any external pull-up resistor. Consider that this is a general configuration, but a particular pin setup must be done on PORTXn registers.

So what we are doing here is showing the MCUCR value, changing it disabling Pull-up (setting bit to one) and showing again the MCUCR value modified.

That’s the result:

MCU Control Registers
———————-
MCUCR: 0

MCU Control Registers
———————-
MCUCR: 10000

Conclusions

I tried to show a great tool to play with Arduino, getting more power and flexibility from  it.

You can access to any register of AVR, read values direct form ADC, setup internal pull-ups, changing parameters in timer/counters, direct control on TWI,…. It’s really great!

In the other hand this possibility involves to know how AVR registers work. So a deep reading and understanding of AVR manual is a must. Be sure your project will work as you wanted to. Is your responsibility, not mine.

Anuncios