Week3 Arduino
Week3 Arduino
CPU
Internal Memory:
• Flash (stores program code)
• SRAM (holds data and variable during execution)
• EEPROM (holds persistent data generated by program)
Peripherals:
• A/D converter (ADC)
• Timers
• UART
• SPI
• DMA
• GPIO
• TWI
• Comparator
• RTC
• WDT
• RNG
• etc.
Connecting
switches in series
+ Power rails
-
https://forum.arduino.cc/t/fully-understand-
pins_arduino-h-for-the-nano-33-ble/628994
Winter 2022 IE5995: IoT & Edge AI Programming 13
Nano 33 BLE Power Tree
}
void loop() {
// put your main code here, to run repeatedly:
Example 1
0x7FFFFFFF
= 0b01111111111111111111111111111111
= 2,147,483,647
Note: standard C does not have syntax for binary literal, the “0b” prefix is a non-standard compiler extension.
Maximum value of long in 32-bit system. In Arduino, the prefix “B” can also be used to denote binary literals (see Binary.h)
Winter 2022 IE5995: IoT & Edge AI Programming 19
Read from Serial
void setup(){ void setup(){
Serial.begin(9600); Serial.begin(9600);
} }
void loop(){ void loop(){
if(Serial.available() > 0){ if(Serial.available() > 0){
byte val = Serial.read(); int val = Serial.parseInt();
Serial.print("Received: "); Serial.print("Received: ");
Serial.println(val); Serial.println(val);
} }
} }
Exercise: Create a program that generates ten, one at a time, two-number addition questions, e.g., 4+7=? After
printing out each question, wait for the user (e.g., a kindergartener) to input an answer, then present the next
question. After 10 questions are answered, print out the number of correct answers and the total time taken to
complete the 10-question test.
#include <stdio.h>
#include <stdint.h>
int main()
{
uint32_t a = 0xF86A81F3;
uint8_t * p = (uint8_t*)&a;
printf("%x %u\n", a, a);
printf("%x %x %x %x\n", *p, *(p+1), *(p+2), *(p+3));
printf("%x\n", (uint8_t)a);
a >>= 8;
printf("%x %u\n", a, a);
printf("%x %x %x %x\n", *p, *(p+1), *(p+2), *(p+3));
}
https://docs.arduino.cc/learn/microcontrollers/analog-output
D9
- 330 ohm
+
GND
Device 1 Device 2
https://www.analog.com/en/analog-dialogue/articles/uart-a-hardware-communication-protocol.html
https://learn.sparkfun.com/tutorials/serial-communication/rules-of-serial
Winter 2022 IE5995: IoT & Edge AI Programming 38
Serial Bridge
void setup() {
• Serial is the USB Serial Port through which the
Serial.begin(115200);
Arduino board connects to the PC
Serial1.begin(115200);
• Serial1 works through the TX / RX pins on the board
}
• Connect two boards and message each other
• Board1’s TX connects to Board2’s RX
void loop() {
• Board1’s RX connects to Board2’s TX
while(Serial.available()){
• Board1’s GND connects to Board2’s GND
Serial1.write(Serial.read());
• Caution: Do not connect a 5 V board with a 3.3 V
}
board
while(Serial1.available()){
• e.g., Do not connect Arduino Uno / Mega (5 V)
Serial.write(Serial1.read());
with Arduino Nano 33 BLE or any Adafruit
}
board (3.3 V)
}
TX buffer RX buffer
bleSerial.available()
RX buffer bleSerial.read() TX buffer Type & send
Serial via keypad
Type some text, TX buffer Serial.write()
hit Ctrl + Enter Display on screen Serial.print()
RX buffer
Serial.available()
Serial.read()
Exercises:
Toggle the LED (connected to D13) whenever pin D3 goes from HIGH to LOW
• Try both the Polling and the Interrupt methods
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}
void loop() {
digitalWrite(ledPin, state);
}
void blink() {
state = !state;
}
This is just for Arduino. It is configured this way to keep things simple. Many processors (e.g., STM32) allow interrupt to occur within an ISR.
Winter 2022 IE5995: IoT & Edge AI Programming 48
Timer Interrupt
• The interrupt is triggered by a hardware timer event
• Whenever a given period of time has elapsed, an interrupt is triggered and the
associated ISR is run, regardless of what the CPU is doing at the moment
• Why use timer interrupt?
• To have the mission-critical task (which is implemented in the ISR) not blocked by ill-
behaving functions / tasks in the main loop
#include <TimerOne.h>
Exercise: finish this code to
void setup(){
• blink the LED at 2 Hz
Timer1.initialize(500); // 500 microseconds per trigger
• generate a 1000 Hz square wave
Timer1.attachInterrupt(callback);
• generate a 1000 Hz PWM signal at
}
10% duty cycle to drive the LED
void callback(){
// Implement the ISR
}
#include <NRF52_MBED_TimerInterrupt.h>
#include <NRF52_MBED_ISR_Timer.h>
NRF52_MBED_Timer ITimer(NRF_TIMER_3);
volatile byte led_val;
void callback(){
led_val = !led_val;
}
void setup(){
ITimer.attachInterruptInterval(500000, callback); Exercise: finish this code to
}
void loop(){ • blink the LED at 2 Hz
digitalWrite(13, led_val); • generate a 1000 Hz square wave
} • generate a 1000 Hz PWM signal at
10% duty cycle to drive the LED
https://github.com/khoih-prog/NRF52_MBED_TimerInterrupt
Winter 2022 IE5995: IoT & Edge AI Programming 52
volatile int flag = 0;
extern "C" {
void TIMER4_IRQHandler_v(){ nRF52840 Timer Interrupt Example
if (NRF_TIMER4->EVENTS_COMPARE[0] == 1){ • Uses nRF MDK
flag++;
NRF_TIMER4->EVENTS_COMPARE[0] = 0;
}
} C:\Users\gn0061\AppData\Local\Arduino15\packages\a
} rduino\hardware\mbed_nano\2.6.1\cores\arduino\mbe
d\targets\TARGET_NORDIC\TARGET_NRF5x\TARGET_SD
void setup() { K_15_0\modules\nrfx\mdk\nrf52840.h
Serial.begin(115200);
Serial.println("Configuring timer"); C:\Users\gn0061\AppData\Local\Arduino15\packages\a
// Refer to definitions in nrf52840.h and nrf52840_bitfield.h rduino\hardware\mbed_nano\2.6.1\cores\arduino\mbe
// 16-bit timer, max count is 65535 d\targets\TARGET_NORDIC\TARGET_NRF5x\TARGET_SD
NRF_TIMER4->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos;
K_15_0\modules\nrfx\mdk\ nrf52840_bitfield.h
// Timer frequency = 16 MHz/2^PRESCALER (pp 460 of nRF52840 Product Specification v1.1)
// So this sets the timer frequency to 16 MHz/2^4 = 1 MHz
NRF_TIMER4->PRESCALER = 4 << TIMER_PRESCALER_PRESCALER_Pos; C:\Users\gn0061\AppData\Local\Arduino15\packages\a
// Sets the capture compare value, cannot exceed 65536 rduino\hardware\mbed_nano\2.6.1\cores\arduino\mbe
// 20000 counts will take 20 ms d\cmsis\CMSIS_5\CMSIS\TARGET_CORTEX_M\Include\c
NRF_TIMER4->CC[0] = 20000; ore_cm4.h
// Enable interrupt for event Compare[0], see pp 464
NRF_TIMER4->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos; https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v
// Sets the shortcuts between event Compare[0] and task CLEAR (i.e., clear time) 1.1.pdf
// That is reset the timer count to 0 when the event occurs
NRF_TIMER4->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
// Function is defined in core_cm4.h
// TIMER4_IRQn is a nrf52840 Specific Interrupt Number, defined in nrf52840.h
// Enables a device specific interrupt in the NVIC interrupt controller.
NVIC_EnableIRQ(TIMER4_IRQn);
// Start the timer, pp 461
NRF_TIMER4->TASKS_START = 1;
This example: Directly access the
} NRF API and implement your
void loop() { own timer interrupt.
Serial.println(flag);
delay(500);
Winter 2022 } IE5995: IoT & Edge AI Programming 53
Arduino code optimization for speed
• Avoid using float
• Floating-point arithmetic is slow on hardware that does not support it
• Use long instead, which can retain more digits of precision, and faster
• Lookup rather than calculate
• Use const byte instead of int for small constants such as Pin names
• Move looping code into the setup function
• the loop() function checks for Serial communication which takes time
• Speeding up Digital IO*
• Directly manipulate the pin bit in the port register * Involves bypassing Arduino functions
• Speeding up Analog Inputs*
• Reducing the prescaler of the Timer that triggers ADC conversions
https://github.com/kriswiner/LSM9DS1/blob/master/LSM9DS1_MS5611_BasicAHRS_t3.ino
https://axodyne.com/2020/06/arduino-nano-33-ble-ahrs/
https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration
#include <Arduino_LSM9DS1.h>
#include <HardwareBLESerial.h>
HardwareBLESerial &bleSerial = HardwareBLESerial::getInstance();
void setup() {
Serial.begin(9600);
while(!bleSerial.beginAndSetupBLE("IE5995"));
while(!IMU.begin());
}
void loop() {
float x, y, z;
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(x, y, z);
bleSerial.poll(); Exercise:
Serial.print(x); bleSerial.print(x); • Write programs to read the gyroscope
Serial.print('\t'); bleSerial.print('\t'); and magnetometer values
Serial.print(y); bleSerial.print(y);
Serial.print('\t'); bleSerial.print('\t'); • Study the source code LSM9DS1.cpp
Serial.println(z); bleSerial.println(z); • Use Wire.h to communicate with
} sensor device via I2C
delay(10); // to avoid flooding bleSerial
}
• The same method can be used to
read other onboard sensors that
has I2C bus
Buffer Buffer
PDM.setBufferSize(1024) // bytes
C:\Users\gn0061\AppData\Local\Arduino15\packages\arduino\hardware\mbed_nano\2.6.1\libraries\PDM
#include <Wire.h>
void trigger(){
Wire1.beginTransmission(LPS22HB_ADDRESS);
Wire1.write(CTRL_REG2);
Wire1.write(0x01);
Wire1.endTransmission();
}
void trigger(){
Wire1.beginTransmission(LPS22HB_ADDRESS);
Wire1.write(CTRL_REG2);
Wire1.write(0x01);
Wire1.endTransmission();
}
bool presReady(){
uint8_t status = read1(LPS22HB_STATUS);
return(status & 0x1);
}
bool tempReady(){
uint8_t status = read1(LPS22HB_STATUS);
return(status & 0x2);
}
uint16_t getTemperature(){
return read1(TEMP_OUT_L) |
read1(TEMP_OUT_H) << 8;
}
uint8_t read1(uint8_t reg){
uint8_t val;
Wire1.beginTransmission(LPS22HB_ADDRESS);
Wire1.write(reg);
Wire1.endTransmission(false); // send restart message
Wire1.requestFrom(LPS22HB_ADDRESS, 1);
val = Wire1.read();
Wire1.endTransmission(true); // send stop message
return(val);
}
Winter 2022 IE5995: IoT & Edge AI Programming 72
trigger();
uint32_t raw_pres;
uint16_t raw_temp;
while(!presReady());
raw_pres = getPressure();
while(!tempReady());
raw_temp = getTemperature();
float pres_hPa = raw_pres / 4096.0;
float temp_F = raw_temp / 100.0;
bool tempReady(){
uint8_t status = read1(LPS22HB_STATUS);
#include <Wire.h> return(status & 0x2);
#define LPS22HB_ADDRESS 0x5C }
#define CTRL_REG2 0x11
#define LPS22HB_STATUS 0x27 uint32_t getPressure(){
#define PRESS_OUT_XL 0x28 return read1(PRESS_OUT_XL) | read1(PRESS_OUT_L) << 8 | read1(PRESS_OUT_H) << 16;
#define PRESS_OUT_L 0x29 }
#define PRESS_OUT_H 0x2A
#define TEMP_OUT_L 0x2B uint16_t getTemperature(){
#define TEMP_OUT_H 0x2C return read1(TEMP_OUT_L) | read1(TEMP_OUT_H) << 8;
char msg[40]; }
nrf52840.h
Read:
Section 5.3.1 Power – Power supply
For implementation, refer to nrf52840.h and nrf52840_bitfield.h in the directory: Section 6.9 GPIO
C:\Users\gn0061\AppData\Local\Arduino15\packages\arduino\hardware\mbed_nano\2.6.1\co
Section 6.10 GPIOTE
res\arduino\mbed\targets\TARGET_NORDIC\TARGET_NRF5x\TARGET_SDK_15_0\modules\nrfx
\mdk