USB Serial firmware for ATmega32U4


This post shows how to create USB Serial firmware for the ATmega32U4 found on Adrafruit’s excellent breakout board, using Atmel Studio 7. The design of the breakout board is available at GitHub, so is the Fritzing part used in the figure below. The source code of the USB Serial firmware discussed here can also be forked at GitHub.

Screen Shot 2016-10-28 at 10.02.24.png

Source code

Creation of source code with Atmel Studio 7 is described in post Arduino USB Serial firmware from scratch. Choose adafruit_u4 as the board for LUFA Board Support (driver).

The code has been adapted to blink the same LED when receiving and transmitting data, because the breakout board has just one programmable LED.

Flash using JTAGICE3

See the wiring diagram above to see how JTAGICE3 can be wired to the ICSP header on the breakout board. The Device Programming dialog can then be used to program flash memory on the MCU as shown below.

screen-shot-2016-10-28-at-10-27-19.png

Test

The converter can be tested by using another USB Serial converter connected to RX and TX wires shown in the wiring diagram. Note that the wire ending with TX should be connected to RX on the other converter, similarly the wire ending with RX should be connected to TX.

Troubleshooting tips

The firmware requires that the host send SetLineCoding request to set the baud rate, as described in Universal Serial Bus Communications Class Subclass Specification for PSTN Devices. If the host fails to do that, the serial port will not get initialized, and data cannot be received from or sent to the host.

The breakout board ships from Adafruit in USB powered mode. That makes it ideal as a USB Serial adapter because it can be powered from the PC it is plugged into. If your USB host device does not provide enough current on VBUS, you can cut the VCC solder jumper on the other side, and provide 3.3V at the VCC header pin.

Screen Shot 2016-11-14 at 12.11.11.png

Atmel has a detailed application note on USB that has recommendations you should take into consideration in your designs.

Advertisements

Unbricking a JTAGICE3


Atmel Studio 7 prompted me to upgrade a JTAGICE3 tool recently. I went ahead with the upgrade since I couldn’t use the tool without it, and I have done it with the JTAGICE mkII on several occasions. After the upgrade was successfully completed, I found the JTAGICE3 in a state that is generally referred as bricked.

I left it aside for a couple of weeks until I decided to visit AVRFREAKS, and found a solution.

You’ll need to put JTAGICE3 in bootloader mode. Short the pads highlighted in the image below, and plug it in.

jtagice3-open.jpg

Then, from Windows command line run

C:\Program Files (x86)\Atmel\Studio\7.0\atbackend>atfw -t jtagice3 -a "C:\Program Files (x86)\Atmel\Studio\7.0\tools\JTAGICE3\jtagice3_fw.zip"

USB Descriptors of Arduino UNO


I’ve been studying the USB interface of Arduino UNO so that I can interface it to an embedded host. It appears as a serial port on Linux, OS X, and Windows 10, without need for custom drivers. The Arduino IDE can reprogram the device over the serial port. Makers also use it to output debug information.

uno.png

 

Here’s the detailed device descriptor as seen on Linux with lsusb -v

Bus 001 Device 005: ID 2341:0043 Arduino SA Uno R3 (CDC ACM)
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            2 Communications
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x2341 Arduino SA
  idProduct          0x0043 Uno R3 (CDC ACM)
  bcdDevice            0.01
  iManufacturer           1
  iProduct                2
  iSerial               220
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           62
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass      2 Abstract (modem)
      bInterfaceProtocol      1 AT-commands (v.25ter)
      iInterface              0
      CDC Header:
        bcdCDC               10.01
      CDC ACM:
        bmCapabilities       0x06
          sends break
          line coding and serial state
      CDC Union:
        bMasterInterface        0
        bSlaveInterface         1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval             255
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 Unused
      bInterfaceProtocol      0
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x04  EP 4 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1

Interface descriptor with class Data Interface Class (bInterfaceClass=0x0A) is used for serial communications. Endpoint with bEndpointAddress 0x03 is used for input, and bEndpointAddress 0x04 for output.

Packaging source code using Grunt


I have this very specific need to package source code of an Atmel Studio 6.2 project. For those not in the know, Atmel Studio 6.2 is based on Visual Studio Isolated Shell, and retains many of the features that make Visual Studio itself a neat IDE.

I had several choices for packaging the source code:

  1. Do it manually – that would have worked once or twice. Since I have to keep some files out of the source package, it would make repeated packaging an error-prone and time-consuming affair.
  2. Use msbuild – I didn’t find a convenient task native to msbuild for creating a zip file. Maybe I didn’t look hard enough.
  3. Use Apache Ant – I didn’t want to include a Java dependency into my build and decided to let Ant go.
  4. Use Grunt – I always seem to have Node.js installed, and find JSON for writing build instructions an interesting alternative to writing XML (verbose). Grunt is also quite portable. Grunt won.

The only files Grunt requires is a package.json file with the project configuration, and a Gruntfile.js with the build instructions.

You can create package.json by invoking npm init and providing some details about your project. Gruntfile.js can be hand-coded in any text editor. Here’s my own script to get you started.

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    compress: {
      main: {
        options: {
          archive: 'demo.zip'
        },
        files: [
          {
            expand: true,
            cwd: './',
            src: ['**', '!*/Debug/**', '!*/Release/**', '!node_modules/**', '!*.atsuo', '!**/file.h', '!demo.zip']
          }
        ]
      }
    }
  });

  // Load tasks
  grunt.loadNpmTasks('grunt-contrib-compress');

  // Default task(s).
  grunt.registerTask('default', ['compress']);

};

To invoke Grunt, you need to have grunt and its plugins installed. Use npm to download and install a project-local copy of these packages, and include them in your package.json as dependencies. In my case

npm install grunt --save-dev
npm install grunt-contrib-compress --save-dev

That results in creation of of a node_modules folder in the root folder of the project. I don’t add node_modules to version control. If you use git, add it to your .gitignore. Other developers can obtain dependencies listed in package.json by invoking npm install within the root folder.

You are now ready to invoke Grunt and execute the relevant tasks. In my case, invoking grunt results in creation of a demo.zip file containing all the files under the project root folder, minus whatever files and folders I choose to leave out.

Memory alignment problems in AVR32


This post summarizes some memory alignment problems I’ve had with AVR32 and Atmel’s GNU toolchain that ships with Atmel Studio 6.2.

INTRAM section length in the linker script

My problem began when I changed the INTRAM section length in the linker script. The code fails, and I am not even able to start a debug session using JTAGICE mkII. Lengths of 0x00007FFC and 0x00008000 work all right, 0x00007FFF does not. The former are a multiple of 4 i.e. 32-bit aligned, the latter is not.

Casting to a pointer of different type

Casting an unsigned char pointer, to pointer to a multi-byte scalar type such as unsigned int, and accessing it, for example *((unsigned int*)(&array[index])), may lead to Data Read Address exception. If you are stuck in that exception handler, you’ve got a memory read alignment problem.

Passing pointers to unaligned members of packed structs

I haven’t (yet) had any problems with packed structs, but beware of passing pointers to members of such structs to other functions. If your architecture does not support unaligned access (AVR32 being one such architecture), the processor may fault when functions try to read or write memory through misaligned pointers. Passing a pointer to the struct itself is fine because the compiler knows it is packed, and will access its members in a safe way.

Migrating to a new version of AVR-GCC toolchain


I have posted in the past about migrating from AVR32 Studio to Atmel Studio 6. In that post, I mention that I am having issues with newer version of the toolchain. In this post I explain why that is so.

The first thing I did is upgrade the Atmel Software Framework (ASF). The version used earlier is 1.7.0, quite dated compared to version 3.15.0 that ships with Atmel Studio 6.2. Updating ASF version alone does not make our issue go away.

Our application uses a Synchronous Serial Controller (SSC) to transmit data. Data is continuously copied from SRAM using a Peripheral DMA Controller (PDCA). PDCA generates an interrupt when it has transmitted the specified data (triggered when TCRR returns to zero). The routine that handles that interrupt, sets the memory address (MARR) and size of data (TCRR) that will be transmitted next.

I got the first hints of where the problem could be when:

  • Debugging with JTAGICE mkII, I’d discover the processor hung at some exception handler (different each time application source is changed and recompiled) such as _handle_Instruction_Address, _handle_Data_Address_Read, _handle_Data_Address_Write etc. Upon looking for an answer, I realized that this is quite common when a stack overflow or buffer overflow has occurred.
  • Analyzing the data transmitted by the SSC using a Saleae Logic 16, I noted that only the first two DMA transfers were actually occurring. These were programmed at initialization, hinting at the fact that the interrupt handler is the source of the problem.

I got a hint for the solution from the AVR32006 : Getting started with GCC for AVR32 application note. Adding __attribute__((interrupt("full"))) to the function definition solves the problem. That tells the compiler to return from the function using the special rete instruction. You can also use the ISR macro to define the interrupt handler function. An example follows

__attribute__((interrupt("full"))) void pdca_interrupt_handler(void)
{
// rearm the PDCA
}

This is how the interrupt handler is registered.

INTC_register_interrupt( (__int_handler) &pdca_interrupt_handler, AVR32_PDCA_IRQ_1, AVR32_INTC_INT0);

Our application uses FreeRTOS, and that appropriately initializes the Interrupt Controller (INTC) and the EVBA system register.

Upgrading to a newer version of Atmel Software Framework


This post is a brief description of the procedure that I follow to upgrade to a newer version of the Atmel Software Framework (ASF).

I have now switched to newer ASF versions so often that it has become second nature. I create a new project from scratch and add the required drivers and services using the ASF Wizard, and copy my own code over to the new project. That is usually all that is required to perform the upgrade. Some project specific settings sometimes need to be copied over manually such as compiler settings and linker script modifications.

If I see any specific API changes, I start from an Example Project supplied with Atmel Studio, study the API using an Evaluation Kit board (EVK), and then change my code appropriately.