WEEK07: embedded programmingThis week we learned about embedded programming. Unlike fancy abtract computer programming using languages like Python or Ruby, the embedded world is a throwback to simpler (funner?) times: direct hardware register manipulation, clock cycle counting, interrupt priorities, datasheet peripheral chapters, and complicated toolchains. It's all worth it when the board you design and solder together starts blinking its LEDs when you tell it to, or at least that's what I tell myself when I'm trying to get a fussy peripheral to work properly. This week our group assignment was to compare the performance and development workflow of a few different architectures; our individual assignment was to (a) read a microcontroller datasheet, and (b) program our boards from circuits week to do something, using as many different languages and environments as possible.
architecture comparisonMy current research at CBA has landed on the Microchip ATSAMD51J20A as the platform of choice. This chip has a lot going for it: a floating-point unit, a fast clock, lots of SRAM, and a relatively straightforward development workflow. Most importantly, it's available and stocked in single-piece quantities in a wafer-level chip scale package (WLCSP), so it's ideal for projects where miniaturization is paramount. My colleague Jake also uses the SAMD51 for his research, so we can share best practices and give each other coding tips. The SAMD51 and the ATTiny44A used in the class board, both shown above, are dramatically different processors, often differing in specifications by an order of magnitude or more. Here is a table comparing the two devices along a few interesting axes:
|characteristic||ATtiny44A, SOIC-14||ATSAMD51J20A, WLCSP-64|
|architecture||AVR||ARM Cortex M4F|
|max clock speed, MHz||20||120|
|package size w/pins, mm^2||51.6||12.6|
|general purpose I/O pins (GPIOs)||12||51|
|input voltage range, V||1.8 - 5.5||1.7 - 3.3|
|datasheet weight if printed on 20-lb paper, lbs||2.3||21.3|
|cost ea., qty 100, USD||0.64||4.08|
|dev environment part||ATtiny44A, SOIC-14||ATSAMD51J20A, WLCSP-64|
|code editor||Atom (or any text editor)||Atom (or any text editor)|
|advanced debugging (breakpoints, etc)?||no||yes|
|how annoying is it to set up?||not very annoying at all||can be a real day ruiner|
the interefoozal dedeslerFirst, credit to Faruk for sharing his delightful project name generator: I have a decent bit of experience with the ATtiny44A and previously wrote a bit of code to control an RGB LED on my class board, so I decided to spin a new design using the SAMD51 to gain some experience on the platform. This also gave me an opportunity to use one of Jake's moduleboards which I am told will play a key part in Machine Week later this semester. The circuit is pretty simple, and is supposed to do two things: (a) use an on-board Hall effect sensor to sense ambient magnetic fields and display the field strength as a bar graph on a dozen LEDs; and (b) use persistence-of-vision to turn the LEDs into a text display, with the Hall effect sensor acting as a zero point to keep the text syncronized. Here is the schematic: ... and the PCB layout: Jake's module is super cool; it breaks out all the SAMD51 pins. I only used the pins along the edge castellations; the bottom of the PCB also has a bunch of pads that can be reflow soldered for access. The board also includes a few holes so the Tag Connect programming cable sits down properly. As usual, I milled the board using mods and the SRM-20. The work produced a suspicious amount of dust: I encountered a few milling defects. First, the 1/64" end mill plunged too deep, despite a single 0.004" pass and proper zeroing. I ran a few iterations of the board and ended up pulling the Z offset up a few tenths of a millimeter; this workaround produced a reasonable result but required a lot of trial and error. Second, the tool path missed a few tiny bridges, highlighted here with red circles: I cut these away with a razor. Erik suggested that I should try increasing my tolerances a bit; I'm running KiCad with 0.4mm spaces and traces, which is pretty much the limit for a 1/64" (0.39 mm) end mill. I'll try opening this up to 0.5 mm next time. After deburring, soldering down the moduleboard was simple and satisfying; I used plenty of flux, so good ventilation was key: [command: ffmpeg -i VID_20191021_145548.mp4 -filter:v "scale=800:-1" -ss 00:00:23.0 -t 00:00:11.0 -c:a copy out.mp4] I used the SAMD51 development environment I'd set up earlier this month; for more information on this, check out the 'bare metal' section from the CBA Hello World page on this chip. Then I spent... an inordinate amount of time trying to get the ADC to work. I verified that the Hall effect sensor was spitting out 1.0 - 2.5 VDC through its resistor divider when I waved a rare earth magnet nearby, but I wasn't able to get the microcontroller to register a value. Here is a snippet of ADC setup code I ended up with:
PORT->Group.PINCFG.bit.PMUXEN = 1; // enable input multiplexer PORT->Group.PMUX.bit.PMUXE = 1; REG_MCLK_APBDMASK |= (1<<7); // enables ADC0 APB clock (should be on by default) REG_GCLK_PCHCTRL40 |= (1<<6); // enables ADC0 generic clock generator REG_GCLK_PCHCTRL40 |= 0x01; // sets ADC0 to generic clock generator 1 REG_ADC0_INPUTCTRL |= 0x04; // set input address to AIN4 (PA4) REG_ADC0_CTRLB |= (1<<1); // turn on free-running mode REG_ADC0_REFCTRL |= 0x03; // set reference to VDDANA ADC0->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_MUXPOS_AIN4; ADC0->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT; // set to 12-bit acquisition mode REG_ADC0_CTRLA |= (1<<1); // set the ENABLE bit to start the ADCI also tried a number of example code snippets I found online. My suspicion is that something weird is going on with the SAMD51's clock; in many cases, the code I found online included a blocking statement that would wait until the ADC reset or enable bit flipped to ensure the peripheral turned on properly. When I included these lines and stopped gdb after a bit of time, I found that my program was hanging while it waited for the bits to flip. More investigation is clearly needed, but I ran out of time for this week. On the plus side, I was able to get the LEDs to work! They're 0805 pink devices I bought from a stall in Huaqiangbei, Shenzhen earlier this year; the reel of 3000 was around $15 USD, so I try to use them for everything. They are rather bright with 120 ohm resistors at 3.3 VDC: I think there is an issue with the updateLEDs() function; here is a video of a simple binary counter, showing a few bits that aren't changing and are probably in the wrong position: [command: ffmpeg -i VID_20191021_145548.mp4 -filter:v "scale=800:-1" -ss 00:00:23.0 -t 00:00:11.0 -c:a copy out.mp4] ... and, we're outta time. Perhaps this project will get dusted off in the future and properly finished. In any case, I'm glad I got a chance to putz about with the SAMD51. Future Zach, please fix my silly mistakes.