AVRSH: A Command Interpreter Shell for Arduino/AVR. using arduino

Ever wanted to be “logged in” to your AVR microcontroller? Ever thought it would be cool to “cat” a register to see its contents? Have you always wanted a way to power up and power down individual peripheral sub-systems of your AVR or Arduino in *real time* ? Me, too, so I wrote the AVR Shell, a UNIX-like shell.

It’s UNIX-like because it’s reminiscent of the shell account you went out and bought to run your irc nick collision bots on, as well as having a command or two in common. It also has a filesystem that resembles UNIX extfs, using an external EEPROM, but that’s become a project unto itself so I’ll be releasing that module separately under a different instructable when it’s production-ready.
AVRSH
Here’s a list of the things you can currently do with the AVR Shell:

    • Read all your Data Direction Registers (DDRn), ports, and pins in real-time
    • Write to all your DDRn’s, ports, and pins to turn on motors, LED’s, or read sensors in real-time
    • List all known registers on the system
    • Create and store values in user-defined variables backed up by EEPROM.
    • Create a root password and authenticate against it (used for telnet access)
    • Read the configured CPU clock speed
    • Change your CPU clock speed by setting a prescaler
    • Start and stop 16-bit timers for timing of various things
    • Power up and/or power down peripheral sub-systems: Analog to Digital Converters (ADC), Serial Peripheral Interface (SPI), Two-wire Interface (TWI/I2C), UART/USART. Useful for when you want to reduce power consumption of the microcontroller or to enable certain functions.
    • Written in C++ with reusable objects.

This instructable will walk through the installation, use, and customization of avrsh.

Step 1: What You’ll Need

This instructable doesn’t require much except that you:

    • Have an Arduino or ATmega328P. Other AVR’s could work, but you may need to modify the code to list any registers that are unique to your MCU. The names only need to match what is listed in the <avr/io*.h> header file unique to your MCU. Many of the register names are the same between AVRs, so your mileage may vary when porting.
    • Have a way to connect to the serial USART of your Arduino/AVR. The system has been tested most extensively with the AVR Terminal, a Windows app that makes a serial connection via your USB or COM port. Works with Arduinos using the USB connection and any AVR using the USB-BUB from Moderndevice.com. Other terminal options include: Putty, minicom (Linux and FreeBSD), screen (Linux/FreeBSD), Hyperterminal, Teraterm. I’ve found putty and teraterm send some garbage when connecting so your first command may be garbled.
    • Have the AVR Shell firmware installed and running, which you can download from these pages, or always get the latest version at BattleDroids.net.

To install the AVR Terminal, just unpack it and run it. To install the AVR Shell firmware, download it and either directly upload the hex file and connect your serial terminal at 9600 baud, or compile it yourself with “make” and then “make program” to upload the hex. Note, you may need to change the AVRDUDE settings to reflect your COM port.

Note: The PROGMEM attribute is broken in the current AVR GCC implementation for C++ and this is a known bug. If you compile it, expect to get many warning messages saying “warning: only initialized variables can be placed into program memory area.” Besides being annoying to see, this warning is harmless. As C++ on the embedded platform isn’t high on the AVR GCC priorities list, it is unknown when this will be fixed. If you check out the code, you will see where I have made work arounds to reduce this warning by implementing my own attribute statements.

Pretty simple. Download and install anything that you might need to then flip the page and let’s get crackin’.

Step 2: Reading and Writing Registers

The AVR Shell was written primarily to access some sensors that I had connected to my AVR. It started with a simple LED then moved to light sensors, temperature sensors, and finally to two ultrasonic transducers. avrsh can set the digital components of these sensors by writing to the registers that control them.

Manipulating AVR registers while running
To get a list of all known registers on your Arduino, type:

and you’ll get a printout looking like this…

I know about the following registers:
TIFR0      PORTC      TIFR1      PORTD      TIFR2      DDRD
PCIFR      DDRB       EIFR       DDRC       EIMSK      PINB
EECR       PINC       EEDR       PIND       SREG       EEARL
GPIOR0     EEARH      GPIOR1     GTCCR      GPIOR2     TCCR0A
TCCR0B     TCNT0      OCR0A      OCR0B      SPCR       SPDR
ACSR       SMCR       MCUSR      MCUCR      SPMCSR     WDTCSR
CLKPR      PRR        OSCCAL     PCICR      EICRA      PCMSK0
PCMSK1     TIMSK0     TIMSK1     TIMSK2     ADCL       ADCH
ADCSRA     ADCSRB     ADMUX      DIDR0      DIDR1      TCCR1A
TCCR1B     TCCR1C     TCNT1L     TCNT1H     ICR1L      ICR1H
OCR1AL     OCR1AH     OCR1BL     OCR1BH     TCCR2A     TCCR2B
TCNT2      OCR2A      OCR2B      ASSR       TWBR       TWSR
TWAR       TWDR       TWCR       TWAMR      UCSR0A     UCSR0B
UCSR0C     UBRR0L     UBRR0H     UDR0       PORTB

root@ATmega328p>

Step 3: Reading and Writing Fuses

Fuses are special types of registers. They control everything from the clock speed of your microcontroller to what programming methods are available to write-protecting EEPROM. Sometimes you will need to change these settings, especially if you’re creating a stand-alone AVR system. I’m not sure you should change your fuse settings on Arduino. Be careful with your fuses; you can lock yourself out if you set them incorrectly.

In a previous instructable, I demonstrated how you can read and set your fuses using your programmer and avrdude. Here, I’ll show you how to read back your fuses at run time to see how your MCU has actually set them. Note, that this isn’t the compile-time setting that you get from the definitions in <avr/io*.h> but the actual fuses as the MCU reads them at run time.

From Table 27-9 in the ATmega328P datasheet (databook, more like it) the bits of the Fuse Low Byte are as follows:

CKDIV8    CKOUT    SUT1    SUT0    CKSEL3    CKSEL2    CKSEL1    CKSEL0

An interesting thing to note is that with fuses, 0 means programmed and a 1 means that that particular bit is unprogrammed. Somewhat counter-intuitive, but once you know it you know it.

AVRSH

  • CKDIV8 sets your CPU clock to be divided by 8. The ATmega328P comes from the factory programmed to use its internal oscillator at 8MHz with CKDIV8 programmed (ie set to 0) giving you a final F_CPU or CPU frequency of 1MHz. On Arduino’s, this is changed since they are configured to use an external oscillator at 16MHz.
  • CKOUT when programmed will output your CPU clock on PB0, which is digital pin 8 on Arduinos.
  • SUT[1..0] specifies the startup time for your AVR.
  • CKSEL[3..0] sets the clock source, such as the internal RC oscillator, external oscillator, etc.

When you read your fuses, it will be returned to you in hexadecimal. This is the format that you need if you want to write the fuses via avrdude. On my arduino, here’s what I get when I read the lower fuse byte:

root@ATmega328p> read lfuseLower Fuse: 0xff

So, all bits are set to 1. I did the same procedure on an Arduino clone and got the same value. Checking one of my stand-alone AVR systems, I got 0xDA which is the value I had set some time back when configuring the chip.

The same procedure is used for checking the High Fuse Byte, Extended Fuse Byte, and Lock fuses. The calibration and signature fuse bytes have been disabled in the code with an #if 0 preprocessor directive, which you can change if you feel scrappy.

 

For more detail: AVRSH: A Command Interpreter Shell for Arduino/AVR.


About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:
LinkedinTwitter

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top