MEAM.Design - ATmega32 Programming - USB Communications


Overview

For either debugging or data communications, it is possible to send and receive data between the ATmega32 and a computer via the same USB port that you use for programming.



Setup

To setup the m2 to communicate over USB, you will need to download the following mUSB-specific support files:

t_usb.h Use this instead of m_usb.h if you are using a Teensy instead of an M2.
t_usb.c Use this instead of m_usb.c if you are using a Teensy instead of an M2.


Be sure to include the C file in your project:

  • For Windows OS users, if you're using Option 1, you will then need to right-click on the Source Files folder, and select Add Existing Source File(s)..., then select the m_usb.c file, and if you're using Option 2, place m_usb.c in src/.
  • For Mac and Linux users, if you're using Option 1, edit your Makefile to add "m_usb.o" after "main.o" on the OBJECTS line, and if you're using Option 2, place m_usb.c in src/.

Also, place the H file next to your main file for Option 1 or place the H file in inc/ for Option 2, and include m_usb.h in your main routine.

Teensy users are using option 2 if you have been following the guide up to this point.



Functions


NOTE - It is assumed that you are running the system clock at 16MHz, though it has been tested to work slower.

As described in the header file, this will give you access to a number of public functions (note - datatype is void unless specified):

          m_usb_init();           Initialize the USB subsystem
char m_usb_isconnected(); Confirm that you have established communication with the PC.
 
unsigned char m_usb_rx_available(); Returns how many bytes are in the receive FIFO buffer (up to 255).
char m_usb_rx_char(); Returns the bottom byte from the receive FIFO buffer or -1 if timeout.
m_usb_rx_flush(); Discard all data in the receive buffer.
 
char m_usb_tx_char(unsigned char c); Add a single 8-bit unsigned char to the transmit buffer. Returns 0 if all is well, -1 if there is an error.
m_usb_tx_hex(unsigned int i); Add a 16-bit unsigned int to the transmit buffer and send as hex-value characters (0000 to FFFF) .
m_usb_tx_uint(unsigned int i); Add a 16-bit unsigned int to the transmit buffer and send as decimal-value characters (0 to 65535).
m_usb_tx_int(int i); Add a 16-bit signed int to the transmit buffer and send as decimal-value characters (-32768 to 32767).
m_usb_tx_ulong(unsigned long l); Add a 32-bit unsigned long to the transmit buffer and send as decimal-value characters (0 to 4294967295).
m_usb_tx_long(long l); Add a 32-bit signed long to the transmit buffer and send as decimal-value characters (-2147483648 to 2147483647).
m_usb_tx_string(char* s); Add a string to the transmit buffer.
m_usb_tx_push(); Immediately transmit all buffered output.


For example, the following code will initialize the USB subsystem, wait for a connection, then wait for a packet to be received and then echo it back to the computer as a decimal number

#include "m_general.h"
#include "m_usb.h"
int main(void)
{
unsigned int value;
m_usb_init();
while(!m_usb_isconnected()); // wait for a connection
while(1)
{
if(m_usb_rx_available())
{
value = m_usb_rx_char();
m_usb_tx_uint(value);
}
}
}




Computer-side connection options

On a PC, open a serial terminal and connect to the proper COM port. Options include:

Use realterm on the GMlab PC's or download putty https://www.putty.org/ for PC or mac.

More directions on how to use this can be found here:

https://pbxbook.com/voip/sputty.html

In Mac OS X, you can also use "screen". For example

screen /dev/tty.usbmodemNUM where NUM is the number of the port

More directions on how to use this can be found here:

https://pbxbook.com/other/mac-tty.html




Other thoughts on USB communications:

AVR CDC Demo Code Hacking
AVR provides some demo code for communication device class (CDC) operation on the ATmega32u4.

This code will compile with AVR-studio, or with a modified Makefile on OS X (Change "avr-gcc.exe" to "avr-gcc". When building, flashing, and running, this causes the ATmega32 to appear as a COM port on a connected host machine. The code is intended to be used with a specific development board that has various other widgets on it (temperature sensor, joystick, etc), but can be modified to send whatever data one wants it to. It gives access to the user by overloading the standard printf() function.

Unfortunately (for the sake of simplicity), the asynchronous digital communication seems to require the use of a process scheduler. The schedule mediates between the usb driver on the MCU and the user-supplied code that actually outputs the data. This means that the user defines two functions:

cdc_task_init() Initialization code
cdc_task() Task code

The task code function will be called repeatedly in a loop by the scheduler, so it needs to return quickly, otherwise the USB communication will be blocked.

The code to build is at the path EVK527-series4-cdc-2_0_2-doc/demo/EVK527-series4-cdc while the rest is support code that we can go through and cut some fat from.