ENG-CANSAT-FEATHER-M0-SKETCH
Forewords
The ATSAMD21 is still a newcomer in the Arduino-compatible world. Most of sketch and libraries would work on ATSAMD21 but somes things have to be pointed out!
Le notes here under would apply to the M0 boards.
Analog reference
If you want to use the ARef for a voltage reference under 3.3v, the line code to use is analogReference(AR_EXTERNAL) with AR_EXTERNAL and not EXTERNAL.
Pins and pull-up
The old way of activating the pull-up resistor was:
pinMode(pin, INPUT)
digitalWrite(pin, HIGH)
Because the pullup-selection register was the same register than output-selection register.
For the M0 (as for many plateform), the code to use is:
pinMode(pin, INPUT_PULLUP)
Serial ou SerialUSB
99.9% of Arduino Sketch does use Serial.print for debugging purpose (or serial output). On the official SAMD/M0 Arduino, this instruction use the Serial5 port which is not exposed on a Feather.
Instead, the USB port on official Arduino M0 is called SerialUSB.
Adafruit did fix this on the Adafruit M0 by redirecting Serial call to USB calls. So, when using a Feather M0 everything appears to work to properly without requiring any changes.
However, if you want to use a, official Arduino SAMD, you will have to use SerialUSB instead of Serial. So the Adafruit produit is better on this point. |
If you want to use an official M0 without the need to change all the Serial.print() call to SerialUSB.print() , then place the following code:
#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
// required for Serial operations on Zero based board
#define Serial '''SERIAL_PORT_USBVIRTUAL'''
#endif
just before the first function definition in the code.
Example:
Crédit: AdaFruit Industries www.adafruit.com
AnalogWrite / PWM on Feather M0
After looking through the SAMD21 datasheet, it appears that some of the options listed in the multiplexer table don't exist on the specific chip used in the Feather M0.
For all SAMD21 chips, there are two peripherals that can generate PWM signals: The Timer/Counter (TC) and Timer/Counter for Control Applications (TCC). Each SAMD21 has multiple copies of each, called 'instances'.
Each TC instance has one count register, one control register, and two output channels. Either channel can be enabled and disabled, and either channel can be inverted. The pins connected to a TC instance can output identical versions of the same PWM waveform, or complementary waveforms.
Each TCC instance has a single count register, but multiple compare registers and output channels. There are options for different kinds of waveform, interleaved switching, programmable dead time, and so on.
The biggest members of the SAMD21 family have five TC instances with two 'waveform output' (WO) channels, and three TCC instances with eight WO channels:
- TC[0-4],WO[0-1]
- TCC[0-2],WO[0-7]
And those are the ones shown in the datasheet's multiplexer tables.
The SAMD21G used in the Feather M0 only has three TC instances with two output channels, and three TCC instances with eight output channels:
- TC[3-5],WO[0-1]
- TCC[0-2],WO[0-7]
By following the signals to the pins made available on a Feather M0, the following pins would not be able to produce PWM signal:
- Analog Pin A5
The following pins can be configured as PWM (without conflict) as long as the SPI, I2C & UART keeps their protocol functions:
- Digital pins 5, 6, 9, 10, 11, 12 et 13
- Analog pins A3 et A4
When only the SPI keeps the protocol function, you can also do PWM on the following pins:
- TX (Digital pin 1)
- SDA (Digital pin 20)
analogWrite() and range of PWM value
When using an AVR (like Arduino Uno), the instruction analogWrite(pin, 255) on a PWM output would result in a permanent HIGH signal on the output PIN.
On a Cortex ARM microcontroler, the output signal would be 255/256th. As a consequence, there is always a small pulse-down to 0v. If you need a continuously HIGH signal then the analogWrite(pin, 255) must be replaced by digitalWrite(pin, HIGH)
Missing Header file
You may have some code using a library not supported by the M0 code. As example, if you have some code containing the following line:
#include <util/delay.h>
Then you will get the following error
fatal error: util/delay.h: No such file or directory #include <util/delay.h> ^ compilation terminated. Error compiling.
Wich allow to identiy the line (and the file) where the error occured. You would just need to include the library loading inside a #ifdef structure like showed:
#if !defined(ARDUINO_ARCH_SAM) && !defined(ARDUINO_ARCH_SAMD) && !defined(ESP8266) && !defined(ARDUINO_ARCH_STM32F2)
#include <util/delay.h>;
#endif
The line here upper would not include the header for the listed architectures.
If the #include is present in your Arduino sketch then you may try to remove the #include line.
Start the Bootloader
On most of the AVRs (like Arduino Uno), simply press the reset button with the microcontroler connected on USB would manually start the bootloader. The bootloader would automatically exists after few seconds.
On a M0 microcontroler, you will have to double click the reset button. You will see the LED pulsing on red meaning that the bootloader is active. Once in this mode, the M0 would stay in the bootloader mode forever (there is no "time out"). Click once again on the "reset" button to restart the microcontroler.
Memory alignment
There is few change that you reach this issue... but being aware of this may help.
If you are using the 8 bits plateform then you probably know that TypeCast can be performed on on variables. Example:
uint8_t mybuffer[4];
float f = (float)mybuffer;
But there is no warranty that this may work properly on 32 bits AVR because mybuffer may not been aligned on 2 or 4 bytes (voir memory alignment on Wikipedia).
An ARM Cortex-M0 can only directly access to data by bloc of 16-bits (every 2 or 4 bytes). Trying to access an even byte (byte in position 1 or 3) would cause an hardware fault and will stop a MCU.
Thankfully, there is a very simple workaround... by using the memcpy function!
uint8_t mybuffer[4];
float f;
memcpy(f, mybuffer, 4)
Floating point conversion (dtostrf)
As for the Arduino AVR, the M0 libraries doesn't offer a full support to convert floating point value to string.
The functions like sprintf would not convert floating point values. Thankfully, the standard AVR-LIBC includes the dtostrf function able to handle this conversion.
Inconveniently, the M0 AVR run-time does not have the dtostrf function! You may see some thread suggesting to #include <avr/dtostrf.h> the dtostrf function. But this will not work on M0 even if it compiles.
Instead, have a look to this discussion thread to find a dtostrf function running proprely:
How many RAM available ?
The ATSAMD21G18 does have 32K of RAM but you may need to monitor the memory usage for some raison. You can to this with the following function:
extern "C" char *sbrk(int i);
int FreeRam () {
char stack_dummy = 0;
return &stack_dummy - sbrk(0);
}
Thanks to this discussion thread on the Arduino forums for the trick!
Store data in the microcontroler Flash
If you use an AVR (Arduino) on regular basis, you may have a chance to use PROGMEM. PROGMEM inform the compiler to store the content of a variable (or a string) into the FLASH memory (to save RAM).
It is a bit more easy on an ARM microcontroler. Just add the word const before the variable name:
const char str[] = "A quite lonnnnnggggggg striiiiiinnnnnnng";
The string is now stored in the FLASH. You can handle the string as it was stored inside the RAM, the compiler would automagically read it from the FLASH (no need for special reading function like those required for PROGMEM variables).
You can easily check where the data is stored! Just print the storage address of the variable:
Serial.print("Address of str $"); Serial.println((int)&str, HEX);
If the adress is:
- equal or greater than $2000000 then the data is in the SRAM.
- between $0000 and $3FFFF then the data is stored in FLASH
Written by Meurisse D. from MC Hobby - License: CC-SA-BY.