Skip to content

8. Embedded programming

Planning

Tasks - Must

  • In group: Compare the performance and development workflows of different architectures
  • Take a look at the datasheet of your microcontroller
  • Use your programmer to program your board to do something

Tasks - Nice to

  • Use interrupts in one of my programs
  • Debug code running on microcontroller
  • Use timers in one of my programs
  • Generate a PWM signal and visualize it on an oscilloscope
  • Try switch debouncing with capacitor

Execution

Group assignment

We compared the workflows when working with arduino boards, ATtiny boards and SAMD boards. We programmed different arduino boards and an ATtiny board using the steps described below. We didn’t have the chance to program a board with a SAMD microcontroller.

This is an overview of the programmers and adapter/bridge boards that can be used in the workflows below.

Arduino

COMPUTER --- Arduino board
Arduino boards come with a preprogrammed bootloader. They’re ready to go: Just connect them via USB and they’re ready for programming and serial communication.

AVR / ATtiny

Programming

COMPUTER --- USB/SERIAL BOARD --- SERIAL/UPDI BOARD --- ATtiny board
We’re not going to use a bootloader for ATtiny boards as programming them via UPDI is simple enough.

To make it possible to program the boards from the arduino IDE I did install megaTinyCore with the following steps:

08_EP/attiny_board_manager_url.jpg 08_EP/install_attiny_board_manager.jpg

  • Under Arduino > Preferences > Additional board manager URLs I added http://drazzy.com/package_drazzy.com_index.json
  • Under Tools > Board > Board manager... I installed megaTinyCore

Once the board manager was installed I was able to select the following options under Tools to program my ATtiny412 board:

08_EP/megatinycore_settings.jpg

Serial communication
COMPUTER --- USB/SERIAL BOARD --- ATtiny board

ARM / SAMD

Bootloader

COMPUTER --- SWD programmer --- SAMD board
To make it possible to program SAMD boards directly from the arduino IDE I installed ArduinoCore-fab-sam with the following steps:

08_EP/samd_board_manager_url.jpg 08_EP/install_samd_board_manager.jpg

  • Under Arduino > Preferences > Additional board manager URLs I added https://raw.githubusercontent.com/qbolsee/ArduinoCore-fab-sam/master/json/package_Fab_SAM_index.json
  • Under Tools > Board > Board manager... I installed Fab SAM core for Arduino

Once the board manager was installed I was ready to burn the bootloader.

08_EP/burn_bootloader_settings.jpg 08_EP/burn_bootloader_output.jpg

In the Tools menu I did:

  • select the Board (in my case D11D14AS)
  • select Programmer to be Amtel EDBG
  • Click Burn Bootloader

edbg

At first I tried to burn the bootloader using edbg but I couldn’t get it to work. These are the steps I tried (just for reference):

brew install hidapi
git clone https://github.com/ataradov/edbg
make all

./edbg/edbg -bpv -e -t samd11 -f sam_ba_SAMD11D14AS.bin
The bootloader binary was downloaded from here

Programming & Serial communication

COMPUTER --- SAMD board
Once the bootloader is on the SAMD microcontroller no additional boards are needed anymore: Just connect it via USB to load programs and for serial communication.

As an example this is a sketch to make the SAMD behave as a USB to serial bridge. The readme explains how to upload the sketch to the board.

Microcontroller datasheet

On my hello world board there is an ATtiny412. There’s a lot of information in the datasheet. These are some sections that are interesting to me:

Make the board do something

In the electronics design week I made a board containing ATtiny412, LED, switch and a phototransistor.

I will write a small program that uses all components: The LED will blink at different speeds depending on the light detected by the phototransistor. The switch allows to choose between 3 modes. Each mode adds a different multiplier to the LED blink delay. The mode selection is handy to tune the blink delay range for different lighting conditions.

At first I did check if the switch is pressed in the main loop. This is not ideal specially when the LED is blinking slowly as I check if the button is pressed only once per blink cycle. That means that it might be necessary to press the button for 2 seconds if that’s the time it takes for one blink. To avoid this limitation I adjusted the program to use an interrupt to detect the switch press. By doing so the mode can be adjusted straight away when the switch is pressed without waiting for any LED blinks.

Serial.println inside interrupt routine

I tried to write a message to serial inside the interrupt routine but it didn’t work and it blocked the entire program. It turns out that it’s failing because serial communication uses interrupts but interrupts are disabled while executing an interrupt routine. There is a more detailed explanation here.

In this video I show how switching mode makes the LED blink slower and slower. Once I’m in mode 3 I put my finger on the phototransistor to shade it and that makes the LED blink faster.

RX/TX connection

When writing the program I printed to serial for debugging purposes. At first it did not work: I designed my board in a way that the boards RX is connected to the Serial adapters RX. This is wrong as RX should be connected to TX. As a quick fix I made a hook up wire that just inverts TX and RX (green and orange wire).

08_EP/rx_tx_invert_wire.jpg

connection header direction

The UPDI and serial headers need to have their pins in the right order to match the ones in the USB serial and UPDI adapter boards. I designed my board in a way that the connector pins connect correctly when my board is upside down. This works but it would be handier fot the boards to connect correctly when they’re all facing up. To make sure I connect my boards correctly I marked the VCC and GND pins on all connectors.

08_EP/connectors_wrong_direction.jpg

USB to serial & UPDI in one

Design and production

While writing the program for my hello world board I found myself continuously plugging and unplugging the UPDI adapter to switch between programming and serial communication for debugging. It would be handy to have a board which can act as both USB to serial and UPDI programmer so I started to design one.

I took the schematic of the USB serial adapter board using the D11C as a starting point for my design. I just had to add a UPDI connector, a resistor and a switch to select between programming and serial communication.

08_EP/usb_serial_with_updi_schematic.jpg

08_EP/usb_serial_with_updi_pcb.jpg

And this is the complete board:

08_EP/usb_serial_with_updi_board.jpg

Bigger microcontroller than necessary

When I finished milling the board I realized that I used the D11D instead of using the D11C. As I already had the board I decided to still go ahead. Even if this microcontroller is overkill there is no reason why I shouldn’t be able to get the board to work with it.

Programming header orientation

The programming header on my board has a different orientation than the ones on the SWD programmer. The header still works if connected properly but it would be clearer to keep the orientation of the programming header the same on all boards.

08_EP/usb_serial_with_updi_programming_header_orientation.jpg

Programming

When I was searching for the sketch to make my SAMD board behave as a USB to serial bridge I found out that Quentin did already design a board which is really similar to mine (USB to serial + UPDI).

I successfully uploaded this sketch to my board.

Testing

When I tried to use my new board as a USB to serial bridge it did not work.

The sketch is using Serial2 and it turns out that Serial2 is mapped to different pins for D11C and D11D.

I could just modify my board and connect RX/TX to the pins 15/14 instead of 5/4 but I want to figure out if I could change the code to make it work.

I wasn’t sure how to tell the microcontroller and the arduino Serial library to use non-standard RX/TX pins so I reached out to Quentin to ask for a hint.

He explained that I could use pins 5/4 for serial by setting them to SERCOM-ALT in the Peripheral Multiplexing register. He did as well point me to this code containing an example of setting this register.

I copied the setup_peripheral method from the example and this is how I eded up using it:

#define PIN_TX 4
#define PIN_RX 5

void setup_peripheral(uint8_t pinNum, EPioPeripheral peripheral) {
    uint8_t pinCfg = (PORT->Group[PORTA].PINCFG[pinNum].reg & PORT_PINCFG_PULLEN);
    if ( pinNum & 1 ) { // odd pin
        uint32_t temp = (PORT->Group[PORTA].PMUX[pinNum >> 1].reg) & PORT_PMUX_PMUXE( 0xF ) ;
        PORT->Group[PORTA].PMUX[pinNum >> 1].reg = temp|PORT_PMUX_PMUXO( peripheral ) ;
    } else { // even pin
        uint32_t temp = (PORT->Group[PORTA].PMUX[pinNum >> 1].reg) & PORT_PMUX_PMUXO( 0xF ) ;
        PORT->Group[PORTA].PMUX[pinNum >> 1].reg = temp|PORT_PMUX_PMUXE( peripheral ) ;
    }
    pinCfg |= PORT_PINCFG_PMUXEN; // Enable peripheral mux
    PORT->Group[PORTA].PINCFG[pinNum].reg = (uint8_t)pinCfg;
}

void setup() {
  setup_peripheral(PIN_TX, PER_SERCOM_ALT);
  setup_peripheral(PIN_RX, PER_SERCOM_ALT);
}

At this point I told the microcontroller to use the non-standard pins but I still had to redefine the pins that the arduino serial library uses.

I tried the following code to redefine the serial pins but it did not work.

#undef PIN_SERIAL2_TX
#define PIN_SERIAL2_TX PIN_TX

#undef PIN_SERIAL2_RX
#define PIN_SERIAL2_RX PIN_RX

At that point I modified my local copy of ArduinoCore-fab-sam D11D pin definition which I found at ~/Library/Arduino15/packages/Fab_SAM_Arduino/hardware/samd/1.6.18-alpha2/var iants/Generic_D11D14AS/variant.h (OSX) and that worked :-)

Afterwards I changed it back to the original values to avoid nasty surprises in the future.

Combine flexible and FR1 board

In the past weeks I made some flexible circuits. The connectors are week points in these circuits as it’s easy to rip the traces off the circuit when plugging/unplugging. This week I’ll make a circuit which consists of flexible and non-flexible parts.

I will make a new UPDI adapter in the hope that I will end up with a stronger circuit than my current fully-flexible one.

08_EP/flex_joint_parts.jpg I started by milling little FR1 circuits for the pin header connectors. On one side of these small boards I will solder through-hole pin headers and on the other side I will attach them to the flexible circuit.

08_EP/flex_joint_rivet_press.jpg To attach the FR1 boards to the flexible circuit I used the rivets that would normally be used as vias in 2-layer boards.

08_EP/flex_joint_complete.jpg Once everything was riveted together I added solder to both sides of the rivets to make the joints stronger.

With this new approach the weak point is the joint between the flexible and non-flexible parts. I still think this board will perform better than the fully-flexible version because there is less stress on the joints between parts than on the connectors. With this new board it’s easy to hold onto the little FR1 boards while plugging/unplugging.

Retrospective

I’m really happy that I managed to put programs on both ATtiny and SAMD boards. By knowing how to do that and having everything setup on my machine, from now on I will be able to just program boards without worrying about learning how to do it and setting up things.

It has been frustrating while I was trying to burn the bootloader on a SAMD board with edbg and it just didn’t work but fortunately Henk showed me how to do it directly form arduino IDE and that works perfectly.

I’m convinced that having a USB - serial board which includes UPDI makes the programming/debugging cycle faster as I can switch between serial and programming mode quickly by just flipping a switch. Unfortunately I didn’t get my new board to fully work yet but I’ll continue trying.


Last update: June 19, 2022