Wednesday, February 24, 2021

AVR (Atmel 8 bit MCU) and C: Get Your Library Card!

Time for another post about moving away from Arduino "Sketch" coding for AVR microprocessors  and digging into Arduino Sketch's underlying language: C/C++. 

I have heard this called "Pure C" or "Embedded-C".  This means: you aren't creating .ino files with the Arduino IDE; Instead you code .c and .h files using the Atmel Studio 7 IDE or something like it.  

Finally you compile the C code, and finally send it to the AVR MPU using a programmer like an Atmel Ice.

the toolset: breadboard, IC, Atmel ICE programmer, and a PDIP based UNO R3 clone. 

I always try to engineer things that are easy to reuse--"good engineering is modular engineering." 

To that end, this week, I tried to write, borrow, and generally cobble together AVR-C code for some of the more popular protocols used to communicate between the MCUs and peripherals, and PC's. I2C, SPI, UART and the 10 bit ADCs built into ATmega328P's come to mind.   

OK, how to do this? First: to make everything work I had to understand the protocols themselves. I found myself using a Pulseview logic analyzer to figure the basics out. 

And I had to understand at a deep level how the AVR's registers are designed, what the important AVR registers do, and so forth. 

All of this took time. So, if you like to study datasheets, scratch your head, and learn new things, Pure C or AVR-C or embedded C whatever you want to call it is a blessing.   

If not, if you just want to your electronics project up and running fast, with minimal digging and puzzling over details, walk, don't run to Arduino and get their latest IDEs. Use that instead.  

  

Note the broken logic probe parts. Cheap probes suck.

But here's the upside to doing this using embedded C: in studying the datasheets you can learn what the IC is really capable of, and sometimes it's more than what you find in an existing Arduino library or sketch examples. For instance, the ATmega 328P AVR's on board ADC's give you the ability, if you use C, to change the gain of the incoming analog signal (no need for voltage dividers). Take a look here, the "Bits:4" section. I don't recall that the sketch language gives you hooks into that? If so I never used it. I will use it now.


I2C RTC clock chip (DS3231, datasheet here).  If you want to learn how I2C really works, try writing code using Embedded C for this chip. Tricky!

In the AVR C world, SPI is pretty easy to code, to the point where bitchy forum moderators made fun of someone for suggesting a library for it needs to exist (here), but none of this is completely easy!

I2C is more complex, and required some studying of the protocol as well as an I2C chips' datasheet. For example, to read the 3231 RTC chip using I2C, a fairly complex dance of bytes have to be sent to the chip and back to do useful things: 


In this case, the 3231's I2C address needs to be bit shifted (address << 1) then a zero or one added to the LSB to determine if the I2C instruction is to write or read.

A square wave created with Pure-C and a DAC.  

With libraries in hand, I tried to use them to do things like read ADC peripherals and create square waves or send waveforms to a scope using different DAC ICs.  

To get the libraries: they are on github: I2C here, SPI here, AVR onboard ADC is here, and here is printf to Serial (useful for debugging) is here. I will update these with fixes and more functionality, so you download any of these you may want to check back from time to time.

I also have example code used to test the libraries but that's specific to chips I had in my parts box like the AD9833. I will post all that at some point as well.

MCP4728 quad DAC dev environment....

Update: 4-5-21 I added an Embedded C library for Microchip's I2C quad DAC: MCP4728.  Get the library at my github Repos here. The 4728.c and .h files work, for the simple example included.   

If you come up with additions or mistakes comment, etc. Have fun!

Sunday, February 7, 2021

Atmel Pure C Studio Setup and Debugging, burning Arduino Bootloaders using Atmel Ice; Why (C)ool Heads Prevail

Hello again from the land of audio ones and zeros. 

I am continuing to move away from using the Arduino IDE for my microcontroller programming needs.  

This time I continue to move towards a more "pure C" approach.  I mostly am doing this to learn how processors, microcontrollers and peripherals work "at a deep level"; Arduino's IDE sometimes shields you from that. 

The move to C won't necessarily save time or make projects easier to finish however. The AudioDiWHY mantra: why make things easy?

I began this learning process a long time ago--post here.  

For this pursuit I am using Arduino Unos and Atmel Studio 7 as well as an Atmel ICE programmer

Leaving the Arduino IDE we quickly see something new (for me anyway):  learning C programming is hard! Pointers?  References? Registers? Mallocs? Dereferencing?  Ampersands?  .h files. At first, you have to love it. No one else will.

But like most other things, once you're in the pool, things start to warm up.

I have decided to try to write my own library for I2C....I can use one that's already done (e.g. here) but it is more educational to write my own or at least modify an existing one to the point I can understand how it--and I2C--works.  Update: 2-24-21 libraries are done, or at least work for the basics.  See the post here.

Clockwise: Bona-Fide Uno, Atmel Ice Programmer, Sacrificial Uno Clono

I didn't get far. Early on in this process I bricked my first Uno. I messed with its fuses (info here--be careful) and yes, it stopped working and could no longer be programmed. 

Much swearing ensued, and then I realized--why am I cursing?  It turns out I had a few extra 328P's, and the clone used a through hole IC (so, I got lucky, I could just remove the dead chip with a chip puller and put in a new one).  

Fixed! 

Can I save the broken MPU?  Probably, information about that (for ATTINY anyway) is here. Is it worth the time?  The blown up MPU is a USD$2.50 part. Nope.  


(Which begs the question: why the tantrums?  It must be other things in my life right (like Covid?) Can I blame it on my parents? Why not. Growing up my dad worked on cars all the time and was constantly swearing at them, kicking them, getting in a terrible mood because of them. And he loves cars! WTF? Whatever.  It was how he rolled, but for me, it serves no purpose; it's not cathartic and it makes me a way worse tech.) 

Enough!

OK on to the next problem. After working perfectly for a few days, the Clone Uno's UART stopped working. Why? well it could be a lot of things, perhaps related to aforementioned fuse issues, but maybe not. 

I want to fix this logically.  

For starters, maybe it's not the microcontroller at all. Is it the terminal program (TeraTerm: good program, free, here) I am using?  

Hooking up a few known good UART devices into the PC running TeraTerm--yields, at best, mixed results. Sometime I saw data in the terminal output, sometimes not. The program should run without issue 100% of the time. So yes, that might be it.  

I booted my old Linux system, here, I know Putty works on the laptop...but the old laptop won't boot. Overall not my day. I'll fix that later.

Back to the W10 system. Welcome to Microsoft Windows hell, where everything that could be easy isn't....these guys are too smart for their own good and light cigars with $500 bills. Sometimes I'd get cryptic messages like "you don't have rights to use COM port 20", even when running TeraTerm with full rights. This one got me stuck for a bit. COM20? Why isn't Tera Term using COM3? 

In windows you use Device Manager to change your COM port configuration but that appeared to be no help until I found the webpage here. You have to show "hidden devices" to delete or modify the "invisible COM ports". 

So: run device manager (start > run > devmgmt.msc)  and then "View > hidden devices".  Yes, I had 18--count 'em--18 hidden com ports.  Right click > Deleted them. 

Wow, that felt good.

Plugged back in the UNO. COM3! Yes!!!!! Now find the COM port in device manager: right click > Port Settings tab > Advanced.  I can change the COM port number now. 

To make sure it all worked, I set the Uno's USB serial port from COM3 to COM4.  Yes, that works too, so this is fixed.

You need device manager's "advanced properties" to show you your stale COM ports.

So why did this COM20 setting occur?  Speculation: I must have messed up my com ports while experimenting with FDTI chips (post here). 

OK, TeraTerm and my COM port configuration are fixed. Does everything work now? No! The Windows term program works again, but UART on the Uno clone still doesn't work.

Looking at the UART output with Sigrok Pulseview--post about getting Pulseview working is here--right off the pins on the UNO clone--the UART signals from the microcontroller appear to be OK.  But out of the UNO's USB port it is still broken. 

To fix that's let's look at how the UNO works for serial communication.  A geniuine UNO board has a second atmel MPU: a 16u2, to do its USB to serial conversion. So there are 2 MPUs on an Uno, and the 16u2 is there primarily to convert USB to serial. I didn't know this; so is it an issue with the 16u2? 

I don't know how to check that. There is an ICSP connector for the 16u2, but if I brick this 2nd CPU I have no idea how I'd fix it, and I need to keep moving here. Maybe I messed up the UART on the 328P <> 16u2 when screwing around with my newbie C I2C code?

OK, let's send everything back to stock Arduino using Atmel Studio. If the USB serial signal works in an Arduino environment it might tell us something more about our issue. And: Burning the Arduino bootloader and setting the 16u2 and 328P MPUs back to their initial Arduino settings is a good thing to know how to do.   

Turns out with Atmel Ice, and maybe other programmers, it's not hard. Good video describing how to do this is here.  

You hook the Atmel ice programmer (ICE is a different programmer than the programmer in the video but the process is exactly the same) up to the UNO, then flash the appropriate optiboot*.hex file into it.  

OK where do you find the optiboot hex file? For me, on my Windows 10 system, it was here:

C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.42.0_x86__mdqgnx93n4wtt\hardware\arduino\avr\bootloaders\optiboot\optiboot_atmega328.hex

But you knew that right?  

Anyway: using Atmel Studio, flash the UNO and then choose the above hex file. That gets Arduino bootloader back into the microprocessor.

But you're not done, you need to set the fuses (carefully):

And: Remember that 0 (no X below) is active with AVR fuses!  You knew this as well right?

UNO ARDUINO FUSE SETTINGS:

BODLEVEL = 2V7

RSTDISBL = [ ]

DWEN = [ ]

SPIEN = [X]

WDTON = [ ]

EESAVE = [ ]

BOOTSZ = 256W_3F00

BOOTRST = [X]  <--HAD TO CHANGE THIS; use Optiboot bootloader 

CKDIV8 = [ ] <--HAD TO CHANGE THIS; Uno expects /8 clock 

CKOUT = [ ]

SUT_CKSEL = EXTXOSC_8MHZ_XX_16KCK_14CK_65MS  <--HAD TO CHANGE THIS; use external Crystal on Uno board

EXTENDED = 0xFD (valid)

HIGH = 0xDE (valid)

LOW = 0xFF (valid) 


Yes, some fuse settings were wrong after programming in the hex file, so I held my breath and reprogrammed the fuses again

With that done, the UNO clone works again as an Arduino....good.  Lesson learned: if you use an UNO to practice Pure C programming, make sure it has a PDIP chip (some use SMD, not easy to replace) so if you "brick" the chip you can swap in a new one easily.

I can run a serial test ino file, and now I can see serial out in the TeraTerm program. Fixed! 

So we know the hardware is OK.

Let's try running test code again using some "pure C" UART code from Atmel studio. Ha!!! Works now! Simple C serial UART test code for Atmel Studio, targeting an UNO, where printf()'s will show up on your serial terminal program set to 8N1, is posted here. You can use that to test your setup if you ever want to experiment with UARTS, Atmel microcontrollers, and AVR C.
 
BTW The SPI > serial arduino bootloader/hardware/dual MPU UNO paradigm is complex, more so than I realized when I started this project. Read more here. Interesting.   

And, happy day: Keeping kool I fixed my ancient Linux system as well, but that's outside the scope of AudioDiWhy. Putty works again.....the clone UNO  to Linux putty works again as well.....here's a poor photo of the term and MPU UART at work:

Nice to see text on the right!  I was lost, now I'm found.


Finally I needed to get debugging working. Inline bebugging (good vid is the concept is here) is not well implemented in the Arduino IDE, so I have been using Atmel's setup for this for a long time now....Atmel uses a proprietary debugging protocol called "Debugwire" for inline debugging for some of their chips. Compare this to industry standard, JTAG--which isn't supported on an UNO.  

Sadly DebugWire is not well documented for us makers--e.g.: good luck finding an Atmel document saying how the protocol is laid out. But it is still useful once set up correctly.

Getting this going for a newbie like me was a bit terrifying at first because I read all over that it's easy to brick your UNO with DebugWire. But again--the Atmel 328P is a $2.50 part.  If I blow it up so be it.  It's the cost of learning how this technology really works.

Here's how to get DebugWire going.

On my Uno clone I had to cut the trace you see below; debugwire won't work without this trace cut.  

that's it--other than this, you can use DebugWire to program and debug an UNO without issue.

DeBugWire works with the indicated trace cut, but Arduino IDE won't.


Really good blog post about the hardware mod for this here. A takeaway: You get into Atmel Studio as always, but choose "DebugWIRE" as your tools for Atmel studio and not "ISP".  

Here is how to do that:

First make sure your project builds without errors.

Once that's done, in Atmel Studio 7, left double click on the project you want to debug in solution explorer (by default "solution explorer" is the column on the right).  A set of tools appears in a column on the left. 

Click on "build" then, choose your programmer. Then from the dropdown to the right of that, choose "DebugWire".  Click OK.

The software will ask you if you want to change your fuse settings; terrifying!  But let the software do this for you. For me, it works. And--when you are done w/ debugwire make sure to switch back to normal ICSP programming mode again ("debug >  Disable DebugWIRE and disconnect"). This resets the fuses back to how they were. 

You can only get out of debugWire when you are in debugwire....otherwise this option isn't available.  So I try to always end my DebugWire session after I am done debugging, otherwise things get confusing.

BTW: If you want to use the UNO for Arduino again you have to reconnect the trace you just cut and reburn the bootloader. 

Before I did anything the reset trace looked to me like it was already cut, but using a continuity tester, it wasn't. Had to cut it.

With that cut, yep, debug wire works. Followed all the instructions as per the video here to get basic debugging going. It worked and it's useful, you can see your variable values at breakpoints, as well as see how all registers are set (Debug > windows > IO). 

Good luck doing any inline debugging with the Arduino IDE--you can't--so arguably inline debugging alone is reason enough to switch to Atmel studio + Atmel ICE for 328P projects, perhaps.

One more thing: for any sort of logic projects it's useful I think to have LEDs with 330ohm resistors in series in your junk box. I have found myself using these frequently when doing the above MPU/MCU  bench work. Instead of having to breadboard dumb LED/resistor pairs every time, I built 10 of these on a single perf board. This took maybe 20 minutes and has saved a lot of time since.  

"You need Schoolin"



OK, onward to my I2C library....time to brick something again.....then back to zero. Ons and Offs!  How much work could this be? The main takeaway for me this time: getting upset about an electronics issue makes no sense. Keep cool, take breaks, and figure it out. The sun will come up tomorrow regardless. See ya next time.

 


    


JTAG to SWD Converter

Readers: If you'd like to build the project featured in today's post, please go to PCBWAY's Community pages--gerber file, KiCAD ...