From d138a266b5fb4953cbb7fd4c315414de3f000b34 Mon Sep 17 00:00:00 2001 From: rbaron Date: Wed, 10 Feb 2021 22:14:25 +0100 Subject: [PATCH] Initial quick and dirty PWM implementation using Adafruit's HardwarePWM.h --- code/parasite/lib/parasite/pwm.cpp | 34 ++++++++++++++++++++++++++++++ code/parasite/lib/parasite/pwm.h | 13 ++++++++++++ code/parasite/platformio.ini | 4 ++-- code/parasite/src/main.cpp | 8 +++++-- resources.md | 10 ++++++++- 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 code/parasite/lib/parasite/pwm.cpp create mode 100644 code/parasite/lib/parasite/pwm.h diff --git a/code/parasite/lib/parasite/pwm.cpp b/code/parasite/lib/parasite/pwm.cpp new file mode 100644 index 0000000..2ae453f --- /dev/null +++ b/code/parasite/lib/parasite/pwm.cpp @@ -0,0 +1,34 @@ +#include "pwm.h" + +#include +#include +#include + +namespace parasite { + +namespace { +// nRF52 PWM specs/guide: +// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpwm.html +// Adafruit's HardwarePWM wapper: +// https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/a86fd9f36c88db96f676cead1e836377a37c7b05/cores/nRF5/HardwarePWM.cpp + +// No scaling. The PWM counter will increase with a frequency of 16MHz. +constexpr unsigned long kPWMFrequencyPrescale = PWM_PRESCALER_PRESCALER_DIV_1; +// In conjunction with the PWM clock frequency, kPWMMaxCounter defines the +// frequency of the square wave. +constexpr int kPWMMaxCounter = 32; +// Since we want a duty cycle of 0.5, we flip the PVM output when the counter +// reaches kPWMMaxCounter / 2/; +constexpr int kPWMFlipCount = kPWMMaxCounter; + +} // namespace + +void SetupSquareWave(int pin_number) { + HwPWM0.addPin(pin_number); + HwPWM0.setClockDiv(PWM_PRESCALER_PRESCALER_DIV_1); + HwPWM0.setMaxValue(kPWMMaxCounter); + HwPWM0.writePin(pin_number, kPWMFlipCount); + HwPWM0.begin(); +} + +} // namespace parasite \ No newline at end of file diff --git a/code/parasite/lib/parasite/pwm.h b/code/parasite/lib/parasite/pwm.h new file mode 100644 index 0000000..4288089 --- /dev/null +++ b/code/parasite/lib/parasite/pwm.h @@ -0,0 +1,13 @@ +#ifndef _PARASITE_PWM_H_ +#define _PARASITE_PWM_H_ + +namespace parasite { + +// This is a simple, single-channel PWM-based square wave generator. +// This only ever works for a single pin. If you call this function +// twice with different pin numbers, nothing good will come out of it. +// I am particularly proud of how well I resisted making this "generic" +// and "reusable". +void SetupSquareWave(int pin_number); +} // namespace parasite +#endif // _PARASITE_PWM_H_ \ No newline at end of file diff --git a/code/parasite/platformio.ini b/code/parasite/platformio.ini index d081b63..8765a57 100644 --- a/code/parasite/platformio.ini +++ b/code/parasite/platformio.ini @@ -10,9 +10,9 @@ [env:e73-tbb] platform = nordicnrf52 -; board = adafruit_feather_nrf52832 +board = adafruit_feather_nrf52832 ; Additionally, I had to force use_adafruit = True in platforms/nordicnrf52/builder/main.py -board = e73-tbb +; board = e73-tbb framework = arduino build_flags = -DNRF52 -DS132 -DNRF51_S132 board_build.ldscript = ./ldscripts/nrf52832_s132_v6.ld \ No newline at end of file diff --git a/code/parasite/src/main.cpp b/code/parasite/src/main.cpp index a200e93..a370de6 100644 --- a/code/parasite/src/main.cpp +++ b/code/parasite/src/main.cpp @@ -1,20 +1,24 @@ #include +#include "pwm.h" + constexpr int kLED1Pin = 17; constexpr int kLED2Pin = 18; +constexpr int kPWMPin = 19; void setup() { Serial.begin(9600); pinMode(kLED1Pin, OUTPUT); pinMode(kLED2Pin, OUTPUT); + parasite::SetupSquareWave(kPWMPin); } void loop() { Serial.print("Hello, world\n"); digitalWrite(kLED1Pin, LOW); digitalWrite(kLED2Pin, LOW); - delay(1000); + delay(500); digitalWrite(kLED1Pin, HIGH); digitalWrite(kLED2Pin, HIGH); - delay(1000); + delay(500); } \ No newline at end of file diff --git a/resources.md b/resources.md index ed08b1c..d10fc2f 100644 --- a/resources.md +++ b/resources.md @@ -94,5 +94,13 @@ if self.board_config(board).get("build.bsp.name", "package"] = "framework-arduinoadafruitnrf52" ``` +## What does each line in the linker mean? +* [The most commented linker script in the world](https://github.com/theacodes/Winterbloom_Castor_and_Pollux/blob/main/firmware/scripts/samd21g18a.ld) + ### Memory layout -The [SoftDevice S132 spec](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fsds_s112%2FSDS%2Fs1xx%2Fmem_usage%2Fmem_resource_map_usage.html&anchor=mem_resource_map_usage) specifies the layout as the soft device begins at addr 0x0 and the application code comes after it, at the address `APP_CODE_BASE`. \ No newline at end of file +The [SoftDevice S132 spec](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fsds_s112%2FSDS%2Fs1xx%2Fmem_usage%2Fmem_resource_map_usage.html&anchor=mem_resource_map_usage) specifies the layout as the soft device begins at addr 0x0 and the application code comes after it, at the address `APP_CODE_BASE`. + +# PWM +* [HardwarePWM.cpp](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/a86fd9f36c88db96f676cead1e836377a37c7b05/cores/nRF5/HardwarePWM.cpp#L112) by Adafruit is a good reference. [Servo.c](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/4d703b6f38262775863a16a603c12aa43d249f04/libraries/Servo/src/nrf52/Servo.cpp#L154) uses it. +* [nrf52832 pwm spec](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpwm.html) +* [nrf5 SDK PWM reference](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v11.0.0%2Fgroup__nrf__pwm__hal.html) HAL => Hardware Abstraction Layer? \ No newline at end of file