RoadTest: SAM D21 Curiosity Nano Evaluation Kit
Author: abrain
Creation date:
Evaluation Type: Development Boards & Tools
Did you receive all parts the manufacturer stated would be included in the package?: True
What other parts do you consider comparable to this product?: Arduino Micro and Nano, microBit, Teensy devices, STM32 Discovery boards
What were the biggest problems encountered?: A dodgy micro-USB cable, selecting the wrong device, an error in the user guide documentation then a mistake with the NVRAM settings bricked the board. The bluetooth click shield is quite old, with the RN-41 module only supporting Bluetooth 2.1 + EDR, and not available from Farnell any more.
Detailed Review:
This is my Roadtest of the Microchip SAM D21 Curiosity Nano Evaluation kitMicrochip SAM D21 Curiosity Nano Evaluation kit.
My aim was to start simply with a classic "blinky" program flashing an LED, before moving on to add the Mikroe Bluetooth Click module, then 2 more Mikroe click modules (the EnvironmentEnvironment and Air Quality 5Air Quality 5 boards) to gather some real world data and store that data locally until collected over the Bluetooth interface.
So far, parts 1 and 2 are complete and written up below, which is as far as communicating over the Bluetooth module, then I hit a bit of a show stopper when getting and storing data from the Environment click board.
So this is the first part of my review into the SAM D21 Curiosity Nano Evaluation kit, the first time I've used one of Microchip's 32 bit devices.
First impressions are good, the kit was nicely packaged, and after just two small issues I've got the classic "blink an LED" program up and running in less than an afternoon!
I'm going to make this a real step-by-step description of how i got something really basic up and running, including the two mistakes I made, so you get to learn along with me, and hopefully it'll all work nicely for you too!
I knew it was a while since I'd updated my MPLAB-X IDE, so I headed over to Microchip's website to download the latest OS-X version of the IDE (v5.40) for my Mac and the corresponding XC32 compiler (v2.41).
I plugged the Curiosity board using a micro-USB cable, and started the IDE.
I selected the option to Create a New Project, and chose a Microchip Embedded Standalone project.
I selected the appropriate family (32-bit MCUs) and device (ATSAM21D). No tool was available to select.
I then selected the XC32 toolchain.
Finally I created a folder and gave the project an appropriate yet imaginative name - SAM21D-Blinky.
That was all the setting up done, now just to write some code! I know my way around the MPLAB-X IDE, having used it on quite a few PIC based projects in the past, so I happily went to the project explorer part of the window, selected source files and created a new main.c file.
You don't get much in the default main.c file, so I made it look like the following.
/* * File: main.c * Author: abrain * * Created on June 13, 2020, 5:36 PM */ #include <xc.h> #define true 1 /*** Macros for LED0 pin ***/ #define LED0_Set() (PORT_REGS->GROUP[1].PORT_OUTSET = 1 << 10) #define LED0_Clear() (PORT_REGS->GROUP[1].PORT_OUTCLR = 1 << 10) #define LED0_Toggle() (PORT_REGS->GROUP[1].PORT_OUTTGL = 1 << 10) #define LED0_Get() (((PORT_REGS->GROUP[1].PORT_IN >> 10)) & 0x01) #define LED0_OutputEnable() (PORT_REGS->GROUP[1].PORT_DIRSET = 1 << 10) #define LED0_InputEnable() (PORT_REGS->GROUP[1].PORT_DIRCLR = 1 << 10) #define LED0_PIN PORT_PIN_PB10 void main(void) { int count = 0; LED0_OutputEnable(); while ( true ) { count++; if ( count > 16000) { count = 0; LED0_Toggle(); } } return; }
Just before writing this, I did a bit of research and downloaded Microchip's example code for Getting started with the SAM 21D Curiosity Nano, and in amongst all that I'd found the plib_port.h file that had those Macros in for setting up the status LED on the board.
I pressed the Green "Play" button on the IDE, and hit my first set of problems!
No tool was selected! I'd noticed that when setting up the project, but hadn't thought enough about it then. There was a light flashing away on the board, so it definitely had power. Had my Mac found the USB connection? I opened up Terminal, and ran the ioreg -P IOUSB command:
% ioreg -p IOUSB
+-o Root <class IORegistryEntry, id 0x100000100, retain 18>
+-o AppleUSBXHCI Root Hub Simulation@00000000 <class AppleUSBRootHubDevice, id 0x10000039a, registered, matched, a$
| +-o USB3.0 Hub@00400000 <class AppleUSBDevice, id 0x10000039c, registered, matched, active, busy 0 (2 ms), retai$
+-o AppleUSBXHCI Root Hub Simulation@14000000 <class AppleUSBRootHubDevice, id 0x1000003ac, registered, matched, a$
+-o USB2.0 Hub@14300000 <class AppleUSBDevice, id 0x1000003ae, registered, matched, active, busy 0 (2 ms), retai$
| +-o USB-C Digital AV Multiport Adapter@14320000 <class AppleUSBDevice, id 0x1000003bc, registered, matched, ac$
%
No signs of anything looking like a Microchip board! After a reboot and much doubting of myself, the USB dongle, etc, I came to suspect the cable, and sure enough, swopping to a different micro-USB cable had this showing up:
% ioreg -p IOUSB
+-o Root <class IORegistryEntry, id 0x100000100, retain 18>
+-o AppleUSBXHCI Root Hub Simulation@00000000 <class AppleUSBRootHubDevice, id 0x10000039a, registered, matched, a$
| +-o USB3.0 Hub@00400000 <class AppleUSBDevice, id 0x10000039c, registered, matched, active, busy 0 (2 ms), retai$
+-o AppleUSBXHCI Root Hub Simulation@14000000 <class AppleUSBRootHubDevice, id 0x1000003ac, registered, matched, a$
+-o USB2.0 Hub@14300000 <class AppleUSBDevice, id 0x1000003ae, registered, matched, active, busy 0 (2 ms), retai$
| +-o USB-C Digital AV Multiport Adapter@14320000 <class AppleUSBDevice, id 0x1000003bc, registered, matched, ac$
+-o nEDBG CMSIS-DAP@14100000 <class AppleUSBDevice, id 0x1000007eb, registered, matched, active, busy 0 (74 ms),$
%
Excellent! Back into the IDE, and still no tool to select. This time I looked a little more closely at the configuration settings - I right clicked on the SAM21D-Blinky project name and selected properties. Sure enough, I'd selected a ATSAM21D. Should I really have selected the ATSAMD21G17D that was actually fitted to the board?
Yes!
I could now select the hardware tool!
Now pressing the green "play" button on the IDE got me much better messages about a successful build, updating the firmware on the device, a message in red that said no configuration bits were going to be set (as I'd not set any in the code), then success!
One flashing LED on the Curiosity board!
That's it for this first part of my RoadTest review!
I feel getting an LED blinking is always a good first step with an embedded development board like this - it shows you've got some good foundations to build on if you've compiled that code, loaded the resulting binary onto the device and made it run, there's so much that can go wrong in just those few steps!
I'll add to / edit this as I do more with this little board and all the add-ons, but I want to keep this moderately up to date as I progress through my RoadTest, as much so I don't leave it all until the end as for anything else really!
The next stage of the project was to get the Bluetooth connection up and running. Looking at some examples and the data sheets showed me just how different this 32-bit device was to the PICs that I've mostly used in the past, and also the STM32 devices I'd also used, and I was going to need some help to make some progress. I turned to Microchip's Harmony tool to configure the device, something I'd not used in the past.
I found a great tutorial on Microchip's web site about creating a "Hello World" application on SAM Microcontrollers using Harmony, and that really got me off to a good start, working through how to use the MPLAB X IDE to install Harmony and create a new Harmony project.
The key difference that I had to make was in the configuration settings when creating the project, where I had to select a SAMD21G17D device.
When using the Clock configuration tool I set the clock frequency to just 8MHz, rather than using the 48MHz in the tutorial.
I got in a real mess for a long time though with an error in the Curiosity Manual documentation. A table in the document lists PB03 and PB02 as the serial lines to use:
I used Harmony to set up UART SERCOM5 at 115,200 baud (without interrupts, rather than SERCOM3 at 9,600 baud with interrupts in the tutorial) to match all that and simply couldn't make any progress at all - no matter what I tried, I couldn't get that serial port to talk to me!
Finally, I looked at a drawing towards the back of the document, with an extract from it showing the debugging connections below:
Not only did this show the swop between Tx and Rx from the microcontroller going to Rx and Tx to the CDC UART, but critically it showed PA22 as Tx and PB22 as Rx.
When you look in the SAM 21D family data sheet for these pins, you see that PA22 is Pin 31, Comm 5 Pad 0, and PB22 is Pin 37, Comm 5 Pad 2, so we set these options in the Harmony Configurator tool:
There was one other step to do too - from the Harmony Tools menu, select Pin Configuration, and scroll down the displayed list until PA22 and PB22 are shown. Change the function in the drop down to match the SERCOM mode selected (the example below shows PA12 and PA13, which we'll be using later).
Once that's done, remember to save the file and press the Generate button so that your source code is updated with the changes you've made - you can waste a lot of time wondering why things don't work if you forget this step!
That worked a lot better! I now had some "Hello, world!" code I could run and transmit out of the serial port on the debugger, so was a lot closer now to being able to send and receive data over the Bluetooth UART provided by the supplied Bluetooth Click shield.
You get a whole lot more "behind the scenes" code and libraries included in your project when you use Harmony, as this shot of my project explorer window shows, and I've barely looked at a lot of it!
I started with the default main.c, and added just a few extra lines like the following to get myself some serial output:
static uint8_t buffer[20] = "Hello, world1\r\n"; // ***************************************************************************** // ***************************************************************************** // Section: Main Entry Point // ***************************************************************************** // ***************************************************************************** int main(void) { /* Initialize all modules */ SYS_Initialize(NULL); SERCOM5_USART_Write(&buffer[0], sizeof (buffer)); while (true) { /* Maintain state machines of all polled MPLAB Harmony modules. */ SYS_Tasks(); } /* Execution should not come here during normal operation */ return ( EXIT_FAILURE); }
That worked well, and got me a good starting point for communicating with the RN-41 module on the Mikroe Bluetooth Click board. I looked at the Curiosity Nano Adaptor and saw that MikroBUS slot 2 used a different UART to the others, Tx2 and Rx2, and that these were routed to PA20 and PA21 on the Curiosity board itself, corresponding to SERCOM3 Pads 2 and 3 (Tx and Rx respectively). I also traced through that RST2 was routed to PB03 on the Curiosity board.
I went back to the Harmony Configurator and set up SERCOM3 as follows:
I also changed the pin settings, as before, then added the real time clock (RTC) module, as it's always handy to have a flashing LED on the board to show things are running:
I read enough of the RN-41 manual to work out that I needed to start with the reset line low then take it high, and to send the module a $$$ command to put it into command mode, ready for receiving commands over the debug UART to interrogate and configure it. Back to the pin configuration tool to set PB03 as a Digital Output pin too, remembering to save the file and generate some code too.
My plan was quite simply to have a "tickCount" increment from the real time clock module, then when a serial connection is made over the Bluetooth, output this tickCount to show how long the module's been up and running. Any other commands would simply get tunnelled through the two serial ports. The code to do all this is as shown below:
static volatile bool isRTCTimerExpired = false; static uint8_t buffer[100] = "$$$\r\n"; static uint32_t tickCount = 0; static void rtcEventHandler(RTC_TIMER32_INT_MASK intCause, uintptr_t context) { if (intCause & RTC_MODE0_INTENSET_CMP0_Msk) { tickCount++; isRTCTimerExpired = true; } } // ***************************************************************************** // ***************************************************************************** // Section: Main Entry Point // ***************************************************************************** // ***************************************************************************** int main(void) { /* Initialize all modules */ SYS_Initialize(NULL); RTC_Timer32CallbackRegister(rtcEventHandler, 0); RTC_Timer32Start(); uint8_t loopCounter = 0; uint8_t ticksSinceLastSent = 200; bool initialised = false; GPIO_PB03_Clear(); while (true) { /* Maintain state machines of all polled MPLAB Harmony modules. */ SYS_Tasks(); if (isRTCTimerExpired == true) { isRTCTimerExpired = false; GPIO_PB10_Toggle(); if (!initialised) { loopCounter++; if (loopCounter == 5) { GPIO_PB03_Set(); sprintf((char*) buffer, "Power on BT\r\n"); SERCOM5_USART_Write(&buffer[0], sizeof (buffer)); } if (loopCounter == 10) { sprintf((char*) buffer, "$$$"); SERCOM3_USART_Write(&buffer[0], sizeof (buffer)); sprintf((char*) buffer, "Sent $$$\r\n"); SERCOM5_USART_Write(&buffer[0], sizeof (buffer)); initialised = true; } } } if (SERCOM5_USART_ReceiverIsReady()) { SERCOM5_USART_Read(&buffer[0], 1); SERCOM3_USART_Write(&buffer[0], 1); ticksSinceLastSent = 0; } if (SERCOM3_USART_ReceiverIsReady()) { SERCOM3_USART_Read(&buffer[0], 1); // if we've reasonably recently sent a command to the // Bluetooth module from our serial port connection, // send this response back, otherwise this is probably // an incoming connection, so respond directly if (ticksSinceLastSent < 200) { SERCOM5_USART_Write(&buffer[0], 1); } else { sprintf((char*) buffer, "Tick count = %lu\r\n", tickCount); SERCOM3_USART_Write(&buffer[0], sizeof (buffer)); } } if (ticksSinceLastSent < 200) { ticksSinceLastSent++; } } /* Execution should not come here during normal operation */ return ( EXIT_FAILURE); } /******************************************************************************* End of File */
I ended up adding a little bit of code to sort out routing of responses from the Bluetooth module. If we got a responses from the Bluetooth module soon after we'd sent it a command, I'd sent that response over our debug connection, but if I'd not recently sent something to the Bluetooth module, it was probably an incoming connection so we should send the TickCount back to the Bluetooth module to the remote connection.
I use a Mac, so once I'd got that software uploaded and had a quick check to make sure the Bluetooth module responded to commands, I made sure Bluetooth was on, and went to open the Bluetooth preferences.
Sure enough, there was a new device listed!
I clicked on the connect button, and soon enough a connection was established:
I opened a terminal window and typed the following to get a list of serial ports.
a@As-MBP % ls /dev/cu*
/dev/cu.Bluetooth-Incoming-Port /dev/cu.RNBT-3389-RNI-SPP
a@As-MBP %
The one starting /dev/cu.RNBT-3389 looked right, so I typed the beginning of that and pressed TAB to get the following to connect to the device.
a@As-MBP % screen /dev/cu.RNBT-3389-RNI-SPP
After the screen cleared, pressing enter a few times got me the rewarding display of the tick count shown below:
I pressed Ctrl-A Ctrl-\ to exit the screen program and return to my terminal. More info on the use of screen can be found by typing man screen in terminal.
I went back to the Bluetooth preferences window where the module was already disconnected, and clicked on the little cross icon to remove that connection to the RNBT module.
So, a bit of a distraction while I found that discrepancy in the documentation about where the debug UART was connected, and quite a steep learning curve with Harmony (and I'm far from an expert yet for sure), but I've now got a working remote Bluetooth connection to the SAM21D Curiosity board - mission accomplished!
Note that the Bluetooth click board is quite old now, so much so that I can't even insert a product link here. I could only get a connection from my Mac, neither phones nor tablets were interested in connecting! This could be related to the RN-41 module onboard this click board only supporting Bluetooth 2.1+EDR.
The next stage of my mission was to add some monitoring of the environment, using Mikroe's Environment Click board, which has a Bosch BME680 device on board.
I plugged the board in next to the Bluetooth click board I'd already got installed.
Before inserting the board, I'd seed that all the modules share the same SCL and SDA pins for I2C, and I'd traced those back to PA12 and PA13 on the Curiosity board. I opened up the Harmony configuration tool and added the SERCOM2 module. Despite the screen shot below showing SERCOM3, the second time around I configured SERCOM2 for I2C Master, as below:
I also remembered to change the pin settings on PA12 and PA13 for SERCOM2, as below:
You can also get a nice graphical display of the pin out too:
I had a good read of the BME680 datasheet, and set about writing some code to extract the raw readings over the I2C interface. I know from previous experience that I2C can take some time, and quite often sensors like this need some time to make their measurements too (especially when you're heating elements to determine gas concentrations....), so it looks a little complicated but there's a simple state machine that works through sending some commands off to the device, then when the I2C isn't busy it goes about getting the results. It's not the prettiest code, but happily works, and means you can keep calling it within a loop until it's complete, and it doesn't block the processor for too long.
int BME680_State = 0; uint8_t addr = 0x00; uint8_t data = 0x00; uint8_t dataBuffer[8]; // we have a simple state machine that only // moves on if the I2C isn't busy - we keep // going until it returns true; bool doBME680() { bool result = false; if (!SERCOM2_I2C_IsBusy()) { switch (BME680_State) { case 0: addr = 0xD0; data = 0x00; SERCOM2_I2C_WriteRead(0x77, &addr, 1, &data, 1); BME680_State++; break; case 1: sprintf((char*) buffer, "BME680 ID = %02X\r\n", data); SERCOM5_USART_Write(&buffer[0], strlen(buffer)); BME680_State++; break; case 2: dataBuffer[0] = 0x72; // set humidity oversampling to 1 dataBuffer[1] = 0x01; SERCOM2_I2C_Write(0x77, dataBuffer, 2); BME680_State++; break; case 3: dataBuffer[0] = 0x74; // set temperature and pressure oversampling and // mode to forced to start a measurement dataBuffer[1] = 0b01010101; SERCOM2_I2C_Write(0x77, dataBuffer, 2); BME680_State++; break; case 4: addr = 0x1D; SERCOM2_I2C_WriteRead(0x77, &addr, 1, &data, 1); BME680_State++; break; case 5: if ( (data & 0x80) == 0x80) { BME680_State++; } else { addr = 0x1D; SERCOM2_I2C_WriteRead(0x77, &addr, 1, &data, 1); } break; case 6: addr = 0x1F; SERCOM2_I2C_WriteRead(0x77, &addr, 1, dataBuffer, 8); BME680_State++; break; case 7: // at this point, the data in the dataBuffer is valid! result = true; BME680_State = 0; break; default : result = true; BME680_State = 0; break; } } return result; }
The code to call this is simply added into my main as follows, and would get me a new set of measurements every 20 seconds:
int main(void) { /* Initialize all modules */ SYS_Initialize(NULL); RTC_Timer32CallbackRegister(rtcEventHandler, 0); RTC_Timer32Start(); sprintf((char*) buffer, "\r\nBooted %s\r\n", __TIME__); SERCOM5_USART_Write(&buffer[0], strlen(buffer)); uint8_t loopCounter = 0; uint8_t ticksSinceLastSent = 200; bool initialised = false; GPIO_PB03_Clear(); int secondsCount = 0; bool BME_Read_Wanted = false; while (true) { /* Maintain state machines of all polled MPLAB Harmony modules. */ SYS_Tasks(); if (isRTCTimerExpired == true) { isRTCTimerExpired = false; GPIO_PB10_Toggle(); if (!initialised) { loopCounter++; if (loopCounter == 5) { GPIO_PB03_Set(); sprintf((char*) buffer, "Power on BT\r\n"); SERCOM5_USART_Write(&buffer[0], strlen(buffer)); } if (loopCounter == 10) { sprintf((char*) buffer, "$$$"); SERCOM3_USART_Write(&buffer[0], strlen(buffer)); sprintf((char*) buffer, "Sent $$$\r\n"); SERCOM5_USART_Write(&buffer[0], strlen(buffer)); initialised = true; } } secondsCount++; // once every now and then, we need to kick off another // measurement of Temperature, Humidity and Pressure if ( secondsCount == 20 ) { BME_Read_Wanted = true; secondsCount = 0; } } if ( BME_Read_Wanted ) { if ( doBME680() ) { BME_Read_Wanted = false; int dataIndex = 0; while ( dataIndex < 8 ) { sprintf((char*) buffer, "Addr[%02X]=%02X\r\n", addr + dataIndex, dataBuffer[dataIndex]); SERCOM5_USART_Write(&buffer[0], strlen (buffer)); dataIndex++; } } } if (SERCOM5_USART_ReceiverIsReady()) { SERCOM5_USART_Read(&buffer[0], 1); SERCOM3_USART_Write(&buffer[0], 1); ticksSinceLastSent = 0; } if (SERCOM3_USART_ReceiverIsReady()) { SERCOM3_USART_Read(&buffer[0], 1); // if we've reasonably recently sent a command to the // Bluetooth module from our serial port connection, // send this response back, otherwise this is probably // an incoming connection, so respond directly if (ticksSinceLastSent < 200) { SERCOM5_USART_Write(&buffer[0], 1); } else { sprintf((char*) buffer, "Tick count = %lu\r\n", tickCount); SERCOM3_USART_Write(&buffer[0], strlen(buffer)); } } if (ticksSinceLastSent < 200) { ticksSinceLastSent++; } } /* Execution should not come here during normal operation */ return ( EXIT_FAILURE); }
So, there we had it - every 20 seconds I was getting some raw measurements, and now there were just really 2 things to do:
- convert those measurements into real world values, using some calibration parameters stored in the BME680, and;
- save those readings into the Non-Volatile RAM onboard the SAMD21 chip.
I started with the second.....
I won't go into the details here, as it doesn't end well - I'd already got the NVRAM module added in Harmony, and I set about looking at the settings for the processor, and somewhere along the way I bricked the Curiosity board! I think I ended up setting some "fuses" so that all the Flash is write protected, but essentially I keep getting an error when I try to program the board:
NVMCtrl error bits set! (STATUS = 0xA, INTFLAG = 0x3)
NVMctrl reports an error
I've read a lot of suggestions on Atmel and Microchip forums, some of which make it look pretty terminal, and I've got Microchip's technical support on the case for an answer too, but right now I've reached the end of the road.
I probably was too ambitious for this RoadTest - I'd also planned on using the Air Quality 5 click, but there's not much detailed information out there about using that board, and I'd need to have re-worked some of Mikroe's own library code for that one, so I probably wasn't going to manage that in the time.
I think everything else ought to have been do-able for me. I might have been a bit of a stretch with a new board, a new chip and some new tools, but they shouldn't have been too far from what I'd used in the past, having used MPLAB-X with PIC16 and PIC24 devices, and some STM32 code using Mikroe's ARM compiler tools and ST Discovery boards too, including the ChibiOS operating system too which I can recommend.
In the end there were just a few too many challenges for me, and it all seems like the SAM21 family are still being brought into Microchip's world of documentation, examples and support.
If I'd not pushed the timescales, I'd have had time to get another board and carry on and get the Environment shield on and working - I'll be a little more careful to not brick the next one, and might use a different approach to storing the data, maybe even to another click shield such as the one that supports microSD. I'm also keen to look at the BLE2 clickBLE2 click board so I can connect up to my phone or tablet and get data to them too, instead of just my PC. That uses the newer RN4020 module and supports both BLE and Bluetooth 4.1, so I'll see how I get on with that, and will either update this or provide a link on to my findings.
Top Comments
Very interesting!
Good review.