summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2021-09-16 11:09:30 +0200
committerVegard Storheil Eriksen <zyp@jvnv.net>2021-09-16 11:09:30 +0200
commitcad5bd6501868f9532d5b4a227ca156f9c9d1d8e (patch)
tree7dce7fe31ed3f85ade53d38fe68b76e540403e5e
parent3c526f3d0b30e200462290651f7c6a5eb30710a2 (diff)
Added NRF52 support.nrf52
-rw-r--r--build_rules9
-rw-r--r--gpio/gpio.h217
-rw-r--r--gpio/gpio_nrf.h83
-rw-r--r--gpio/gpio_stm32.h202
-rw-r--r--ld_scripts/nrf52840.ld6
-rw-r--r--radio/radio.h115
-rw-r--r--usb/usb.h5
-rw-r--r--usb/usb_nrf.h187
-rw-r--r--usb/usb_nrf_def.h97
9 files changed, 721 insertions, 200 deletions
diff --git a/build_rules b/build_rules
index fc7fd75..ddc9647 100644
--- a/build_rules
+++ b/build_rules
@@ -109,12 +109,21 @@ def select_stm32(env, variant):
print 'Unknown stm32 family: %s' % family
Exit(1)
+def select_nrf(env, variant):
+ if variant == 'nrf52840':
+ select_arm(env, 'cortex-m4f')
+ env.Append(CPPDEFINES = ['NRF52840'])
+ env['LINK_SCRIPT'] = 'nrf52840.ld'
+
def SelectMCU(env, mcu, variant_dir = None):
mcu = mcu.lower()
if mcu.startswith('stm32'):
select_stm32(env, mcu)
+ elif mcu.startswith('nrf'):
+ select_nrf(env, mcu)
+
else:
print 'Unknown MCU: %s' % mcu
Exit(1)
diff --git a/gpio/gpio.h b/gpio/gpio.h
index 392b2f7..bb4201e 100644
--- a/gpio/gpio.h
+++ b/gpio/gpio.h
@@ -1,218 +1,25 @@
-#ifndef GPIO_H
-#define GPIO_H
-
-#include <stdint.h>
-
-struct GPIO_reg_t {
- #if defined(STM32F1)
- volatile uint32_t CRL;
- volatile uint32_t CRH;
- volatile uint32_t IDR;
- volatile uint32_t ODR;
- volatile uint32_t BSRR;
- volatile uint32_t BRR;
- volatile uint32_t LCKR;
- #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
- volatile uint32_t MODER;
- volatile uint32_t OTYPER;
- volatile uint32_t OSPEEDR;
- volatile uint32_t PUPDR;
- volatile uint32_t IDR;
- volatile uint32_t ODR;
- volatile uint32_t BSRR;
- volatile uint32_t LCKR;
- volatile uint32_t AFRL;
- volatile uint32_t AFRH;
- #endif
-};
-
-class GPIO_t {
- public:
- GPIO_reg_t& reg;
-
- class Pin {
- private:
- const GPIO_t& g;
- int n;
-
- public:
- constexpr Pin(const GPIO_t& gpio, int pin) : g(gpio), n(pin) {}
-
- enum Mode {
- #if defined(STM32F1)
- Input = 0x4,
- InputPull = 0x8,
- Output = 0x3,
- AF = 0xb,
- Analog = 0x0,
- #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
- Input,
- Output,
- AF,
- Analog,
- #endif
- };
-
- enum Type {
- PushPull,
- OpenDrain,
- };
-
- enum Pull {
- PullNone,
- PullUp,
- PullDown,
- };
-
- enum Speed {
- Low,
- Medium,
- Fast,
- High,
- };
-
- void set_mode(Mode m) {
- #if defined(STM32F1)
- if(n < 8) {
- g.reg.CRL = (g.reg.CRL & ~(0xf << (n * 4))) | m << (n * 4);
- } else {
- g.reg.CRH = (g.reg.CRH & ~(0xf << (n * 4 - 32))) | m << (n * 4 - 32);
- }
- #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
- g.reg.MODER = (g.reg.MODER & ~(3 << (n * 2))) | m << (n * 2);
- #endif
- }
-
- void set_type(Type t) {
- #if defined(STM32F1)
- // TODO: Unified configure() method?
- #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
- if(t) {
- g.reg.OTYPER |= 1 << n;
- } else {
- g.reg.OTYPER &= ~(1 << n);
- }
- #endif
- }
-
- void set_pull(Pull p) {
- #if defined(STM32F1)
- // TODO: Unified configure() method?
- #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
- g.reg.PUPDR = (g.reg.PUPDR & ~(3 << (n * 2))) | p << (n * 2);
- #endif
- }
-
- void set_af(int af) {
- #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
- if(n < 8) {
- g.reg.AFRL = (g.reg.AFRL & ~(0xf << (n * 4))) | af << (n * 4);
- } else {
- g.reg.AFRH = (g.reg.AFRH & ~(0xf << (n * 4 - 32))) | af << (n * 4 - 32);
- }
- #endif
- }
-
- void set_speed(Speed s) {
- #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
- g.reg.OSPEEDR = (g.reg.OSPEEDR & ~(3 << (n * 2))) | s << (n * 2);
- #endif
- }
-
- void on() {
- g.reg.BSRR = 1 << n;
- }
-
- void off() {
- g.reg.BSRR = 1 << 16 << n;
- }
-
- void set(bool value) {
- if(value) {
- on();
- } else {
- off();
- }
- }
-
- bool get() {
- return g.reg.IDR & (1 << n);
- }
-
- void toggle() {
- set(!(g.reg.ODR & (1 << n)));
- }
- };
-
- class PinArray {
- private:
- const GPIO_t& g;
- int f;
- int l;
-
- constexpr uint32_t mask1() {
- return ((2 << l) - 1) ^ ((1 << f) - 1);
- }
-
- constexpr uint32_t mask2() {
- return ((4 << (l * 2)) - 1) ^ ((1 << (f * 2)) - 1);
- }
-
- public:
- constexpr PinArray(const GPIO_t& gpio, int first, int last) : g(gpio), f(first), l(last) {}
-
- #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
- void set_mode(Pin::Mode m) {
- g.reg.MODER = (g.reg.MODER & ~mask2()) | ((0x55555555 * m) & mask2());
- }
-
- void set_type(Pin::Type t) {
- g.reg.OTYPER = (g.reg.OTYPER & ~mask2()) | ((0x55555555 * t) & mask2());
- }
-
- void set_pull(Pin::Pull p) {
- g.reg.PUPDR = (g.reg.PUPDR & ~mask2()) | ((0x55555555 * p) & mask2());
- }
- #endif
-
- void set(uint16_t value) {
- value <<= f;
- g.reg.BSRR = ((~value & mask1()) << 16) | (value & mask1());
- }
-
- uint16_t get() {
- return (g.reg.IDR & mask1()) >> f;
- }
- };
-
- constexpr GPIO_t(uint32_t reg_addr) : reg(*(GPIO_reg_t*)reg_addr) {}
-
- constexpr Pin operator[](int pin) {
- return Pin(*this, pin);
- }
-
- constexpr PinArray array(int first, int last) {
- return PinArray(*this, first, last);
- }
-};
-
-typedef GPIO_t::Pin Pin;
-typedef GPIO_t::PinArray PinArray;
+#ifndef LAKS_GPIO_GPIO_H
+#define LAKS_GPIO_GPIO_H
#if defined(STM32F1)
+#include "gpio_stm32.h"
static GPIO_t GPIOA(0x40010800);
static GPIO_t GPIOB(0x40010c00);
static GPIO_t GPIOC(0x40011000);
static GPIO_t GPIOD(0x40011400);
static GPIO_t GPIOE(0x40011800);
+
#elif defined(STM32F3)
+#include "gpio_stm32.h"
static GPIO_t GPIOA(0x48000000);
static GPIO_t GPIOB(0x48000400);
static GPIO_t GPIOC(0x48000800);
static GPIO_t GPIOD(0x48000c00);
static GPIO_t GPIOE(0x48001000);
static GPIO_t GPIOF(0x48001400);
+
#elif defined(STM32F4)
+#include "gpio_stm32.h"
static GPIO_t GPIOA(0x40020000);
static GPIO_t GPIOB(0x40020400);
static GPIO_t GPIOC(0x40020800);
@@ -222,19 +29,29 @@ static GPIO_t GPIOF(0x40021400);
static GPIO_t GPIOG(0x40021800);
static GPIO_t GPIOH(0x40021c00);
static GPIO_t GPIOI(0x40022000);
+
#elif defined(STM32L0)
+#include "gpio_stm32.h"
static GPIO_t GPIOA(0x50000000);
static GPIO_t GPIOB(0x50000400);
static GPIO_t GPIOC(0x50000800);
static GPIO_t GPIOD(0x50000c00);
static GPIO_t GPIOH(0x50001c00);
+
#elif defined(STM32WB)
+#include "gpio_stm32.h"
static GPIO_t GPIOA(0x48000000);
static GPIO_t GPIOB(0x48000400);
static GPIO_t GPIOC(0x48000800);
static GPIO_t GPIOD(0x48000c00);
static GPIO_t GPIOE(0x48001000);
static GPIO_t GPIOH(0x48001c00);
+
+#elif defined(NRF52840)
+#include "gpio_nrf.h"
+static GPIO_t P0(0x50000000);
+static GPIO_t P1(0x50000300);
+
#endif
#endif
diff --git a/gpio/gpio_nrf.h b/gpio/gpio_nrf.h
new file mode 100644
index 0000000..44c85f4
--- /dev/null
+++ b/gpio/gpio_nrf.h
@@ -0,0 +1,83 @@
+#ifndef LAKS_GPIO_GPIO_NRF_H
+#define LAKS_GPIO_GPIO_NRF_H
+
+#include <stdint.h>
+
+struct GPIO_reg_t {
+ uint32_t _reserved;
+ volatile uint32_t OUT;
+ volatile uint32_t OUTSET;
+ volatile uint32_t OUTCLR;
+ volatile uint32_t IN;
+ volatile uint32_t DIR;
+ volatile uint32_t DIRSET;
+ volatile uint32_t DIRCLR;
+ volatile uint32_t LATCH;
+ volatile uint32_t DETECTMODE;
+ uint32_t _reserved_1[118];
+ volatile uint32_t PIN_CNF[32];
+};
+
+class GPIO_t {
+ public:
+ GPIO_reg_t& reg;
+
+ class Pin {
+ private:
+ const GPIO_t& g;
+ int n;
+
+ public:
+ constexpr Pin(const GPIO_t& gpio, int pin) : g(gpio), n(pin) {}
+
+ enum Mode {
+ Input,
+ Output,
+ };
+
+ void set_mode(Mode m) {
+ switch(m) {
+ case Input:
+ g.reg.DIRCLR = 1 << n;
+ break;
+ case Output:
+ g.reg.DIRSET = 1 << n;
+ break;
+ }
+ }
+
+ void on() {
+ g.reg.OUTSET = 1 << n;
+ }
+
+ void off() {
+ g.reg.OUTCLR = 1 << n;
+ }
+
+ void set(bool value) {
+ if(value) {
+ on();
+ } else {
+ off();
+ }
+ }
+
+ bool get() {
+ return g.reg.IN & (1 << n);
+ }
+
+ void toggle() {
+ set(!(g.reg.OUT & (1 << n)));
+ }
+ };
+
+ constexpr GPIO_t(uint32_t reg_addr) : reg(*(GPIO_reg_t*)(reg_addr + 0x500)) {}
+
+ constexpr Pin operator[](int pin) {
+ return Pin(*this, pin);
+ }
+};
+
+typedef GPIO_t::Pin Pin;
+
+#endif
diff --git a/gpio/gpio_stm32.h b/gpio/gpio_stm32.h
new file mode 100644
index 0000000..635bcc9
--- /dev/null
+++ b/gpio/gpio_stm32.h
@@ -0,0 +1,202 @@
+#ifndef LAKS_GPIO_GPIO_STM32_H
+#define LAKS_GPIO_GPIO_STM32_H
+
+#include <stdint.h>
+
+struct GPIO_reg_t {
+ #if defined(STM32F1)
+ volatile uint32_t CRL;
+ volatile uint32_t CRH;
+ volatile uint32_t IDR;
+ volatile uint32_t ODR;
+ volatile uint32_t BSRR;
+ volatile uint32_t BRR;
+ volatile uint32_t LCKR;
+ #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
+ volatile uint32_t MODER;
+ volatile uint32_t OTYPER;
+ volatile uint32_t OSPEEDR;
+ volatile uint32_t PUPDR;
+ volatile uint32_t IDR;
+ volatile uint32_t ODR;
+ volatile uint32_t BSRR;
+ volatile uint32_t LCKR;
+ volatile uint32_t AFRL;
+ volatile uint32_t AFRH;
+ #endif
+};
+
+class GPIO_t {
+ public:
+ GPIO_reg_t& reg;
+
+ class Pin {
+ private:
+ const GPIO_t& g;
+ int n;
+
+ public:
+ constexpr Pin(const GPIO_t& gpio, int pin) : g(gpio), n(pin) {}
+
+ enum Mode {
+ #if defined(STM32F1)
+ Input = 0x4,
+ InputPull = 0x8,
+ Output = 0x3,
+ AF = 0xb,
+ Analog = 0x0,
+ #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
+ Input,
+ Output,
+ AF,
+ Analog,
+ #endif
+ };
+
+ enum Type {
+ PushPull,
+ OpenDrain,
+ };
+
+ enum Pull {
+ PullNone,
+ PullUp,
+ PullDown,
+ };
+
+ enum Speed {
+ Low,
+ Medium,
+ Fast,
+ High,
+ };
+
+ void set_mode(Mode m) {
+ #if defined(STM32F1)
+ if(n < 8) {
+ g.reg.CRL = (g.reg.CRL & ~(0xf << (n * 4))) | m << (n * 4);
+ } else {
+ g.reg.CRH = (g.reg.CRH & ~(0xf << (n * 4 - 32))) | m << (n * 4 - 32);
+ }
+ #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
+ g.reg.MODER = (g.reg.MODER & ~(3 << (n * 2))) | m << (n * 2);
+ #endif
+ }
+
+ void set_type(Type t) {
+ #if defined(STM32F1)
+ // TODO: Unified configure() method?
+ #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
+ if(t) {
+ g.reg.OTYPER |= 1 << n;
+ } else {
+ g.reg.OTYPER &= ~(1 << n);
+ }
+ #endif
+ }
+
+ void set_pull(Pull p) {
+ #if defined(STM32F1)
+ // TODO: Unified configure() method?
+ #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
+ g.reg.PUPDR = (g.reg.PUPDR & ~(3 << (n * 2))) | p << (n * 2);
+ #endif
+ }
+
+ void set_af(int af) {
+ #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
+ if(n < 8) {
+ g.reg.AFRL = (g.reg.AFRL & ~(0xf << (n * 4))) | af << (n * 4);
+ } else {
+ g.reg.AFRH = (g.reg.AFRH & ~(0xf << (n * 4 - 32))) | af << (n * 4 - 32);
+ }
+ #endif
+ }
+
+ void set_speed(Speed s) {
+ #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
+ g.reg.OSPEEDR = (g.reg.OSPEEDR & ~(3 << (n * 2))) | s << (n * 2);
+ #endif
+ }
+
+ void on() {
+ g.reg.BSRR = 1 << n;
+ }
+
+ void off() {
+ g.reg.BSRR = 1 << 16 << n;
+ }
+
+ void set(bool value) {
+ if(value) {
+ on();
+ } else {
+ off();
+ }
+ }
+
+ bool get() {
+ return g.reg.IDR & (1 << n);
+ }
+
+ void toggle() {
+ set(!(g.reg.ODR & (1 << n)));
+ }
+ };
+
+ class PinArray {
+ private:
+ const GPIO_t& g;
+ int f;
+ int l;
+
+ constexpr uint32_t mask1() {
+ return ((2 << l) - 1) ^ ((1 << f) - 1);
+ }
+
+ constexpr uint32_t mask2() {
+ return ((4 << (l * 2)) - 1) ^ ((1 << (f * 2)) - 1);
+ }
+
+ public:
+ constexpr PinArray(const GPIO_t& gpio, int first, int last) : g(gpio), f(first), l(last) {}
+
+ #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) || defined(STM32WB)
+ void set_mode(Pin::Mode m) {
+ g.reg.MODER = (g.reg.MODER & ~mask2()) | ((0x55555555 * m) & mask2());
+ }
+
+ void set_type(Pin::Type t) {
+ g.reg.OTYPER = (g.reg.OTYPER & ~mask2()) | ((0x55555555 * t) & mask2());
+ }
+
+ void set_pull(Pin::Pull p) {
+ g.reg.PUPDR = (g.reg.PUPDR & ~mask2()) | ((0x55555555 * p) & mask2());
+ }
+ #endif
+
+ void set(uint16_t value) {
+ value <<= f;
+ g.reg.BSRR = ((~value & mask1()) << 16) | (value & mask1());
+ }
+
+ uint16_t get() {
+ return (g.reg.IDR & mask1()) >> f;
+ }
+ };
+
+ constexpr GPIO_t(uint32_t reg_addr) : reg(*(GPIO_reg_t*)reg_addr) {}
+
+ constexpr Pin operator[](int pin) {
+ return Pin(*this, pin);
+ }
+
+ constexpr PinArray array(int first, int last) {
+ return PinArray(*this, first, last);
+ }
+};
+
+typedef GPIO_t::Pin Pin;
+typedef GPIO_t::PinArray PinArray;
+
+#endif
diff --git a/ld_scripts/nrf52840.ld b/ld_scripts/nrf52840.ld
new file mode 100644
index 0000000..7542734
--- /dev/null
+++ b/ld_scripts/nrf52840.ld
@@ -0,0 +1,6 @@
+MEMORY {
+ flash (rx) : org = 0x00000000, len = 1024k
+ ram (rwx) : org = 0x20000000, len = 256k
+}
+
+INCLUDE "arm_flash_ram.ld"
diff --git a/radio/radio.h b/radio/radio.h
new file mode 100644
index 0000000..010db43
--- /dev/null
+++ b/radio/radio.h
@@ -0,0 +1,115 @@
+#ifndef LAKS_RADIO_RADIO_H
+#define LAKS_RADIO_RADIO_H
+
+class RADIO_NRF_t {
+ private:
+ struct tasks_t {
+ volatile uint32_t TXEN;
+ volatile uint32_t RXEN;
+ volatile uint32_t START;
+ volatile uint32_t STOP;
+ volatile uint32_t DISABLE;
+ volatile uint32_t RSSISTART;
+ volatile uint32_t RSSISTOP;
+ volatile uint32_t BCSTART;
+ volatile uint32_t BCSTOP;
+ volatile uint32_t EDSTART;
+ volatile uint32_t EDSTOP;
+ volatile uint32_t CCASTART;
+ volatile uint32_t CCASTOP;
+ };
+
+ struct events_t {
+ volatile uint32_t READY;
+ volatile uint32_t ADDRESS;
+ volatile uint32_t PAYLOAD;
+ volatile uint32_t END;
+ volatile uint32_t DISABLED;
+ volatile uint32_t DEVMATCH;
+ volatile uint32_t DEVMISS;
+ volatile uint32_t RSSIEND;
+ uint32_t _reserved[2];
+ volatile uint32_t BCMATCH;
+ uint32_t _reserved_1;
+ volatile uint32_t CRCOK;
+ volatile uint32_t CRCERROR;
+ volatile uint32_t FRAMESTART;
+ volatile uint32_t EDEND;
+ volatile uint32_t EDSTOPPED;
+ volatile uint32_t CCAIDLE;
+ volatile uint32_t CCABUSY;
+ volatile uint32_t CCASTOPPED;
+ volatile uint32_t RATEBOOST;
+ volatile uint32_t TXREADY;
+ volatile uint32_t RXREADY;
+ volatile uint32_t MHRMATCH;
+ uint32_t _reserved_2[3];
+ volatile uint32_t PHYEND;
+ };
+
+ struct reg_t {
+ volatile uint32_t SHORTS;
+ uint32_t _reserved[63];
+ volatile uint32_t INTEN;
+ volatile uint32_t INTENSET;
+ volatile uint32_t INTENCLR;
+ uint32_t _reserved_1[61];
+ volatile uint32_t CRCSTATUS;
+ uint32_t _reserved_2;
+ volatile uint32_t RXMATCH;
+ volatile uint32_t RXCRC;
+ volatile uint32_t DAI;
+ volatile uint32_t PDUSTAT;
+ uint32_t _reserved_3[59];
+ volatile uint32_t PACKETPTR;
+ volatile uint32_t FREQUENCY;
+ volatile uint32_t TXPOWER;
+ volatile uint32_t MODE;
+ volatile uint32_t PCNF0;
+ volatile uint32_t PCNF1;
+ volatile uint32_t BASE[2];
+ volatile uint32_t PREFIX[2];
+ volatile uint32_t TXADDRESS;
+ volatile uint32_t RXADDRESSES;
+ volatile uint32_t CRCCNF;
+ volatile uint32_t CRCPOLY;
+ volatile uint32_t CRCINIT;
+ uint32_t _reserved_4;
+ volatile uint32_t TIFS;
+ volatile uint32_t RSSISAMPLE;
+ uint32_t _reserved_5;
+ volatile uint32_t STATE;
+ volatile uint32_t DATAWHITEIV;
+ uint32_t _reserved_6[2];
+ volatile uint32_t BCC;
+ uint32_t _reserved_7[39];
+ volatile uint32_t DAB[8];
+ volatile uint32_t DAP[8];
+ volatile uint32_t DACNF;
+ volatile uint32_t MHRMATCHCONF;
+ volatile uint32_t MHRMATCHMAS;
+ uint32_t _reserved_8;
+ volatile uint32_t MODECNF0;
+ uint32_t _reserved_9[3];
+ volatile uint32_t SFD;
+ volatile uint32_t EDCNT;
+ volatile uint32_t EDSAMPLE;
+ volatile uint32_t CCACTRL;
+ uint32_t _reserved_10[611];
+ volatile uint32_t POWER;
+ };
+
+ public:
+ tasks_t& tasks;
+ events_t& events;
+ reg_t& reg;
+
+ RADIO_NRF_t(uint32_t reg_addr) :
+ tasks(*(tasks_t*)(reg_addr + 0x0)),
+ events(*(events_t*)(reg_addr + 0x100)),
+ reg(*(reg_t*)(reg_addr + 0x200)) {}
+};
+
+static RADIO_NRF_t RADIO(0x40001000);
+
+#endif
diff --git a/usb/usb.h b/usb/usb.h
index e57867c..260af9f 100644
--- a/usb/usb.h
+++ b/usb/usb.h
@@ -22,6 +22,11 @@ static L0_USB_t USB(0x40005c00, 0x40006000);
static L0_USB_t USB(0x40006800, 0x40006c00);
+#elif defined(NRF52840)
+#include "usb_nrf.h"
+
+static USB_NRF_t USBD(0x40027000);
+
#endif
#endif
diff --git a/usb/usb_nrf.h b/usb/usb_nrf.h
new file mode 100644
index 0000000..16e40a1
--- /dev/null
+++ b/usb/usb_nrf.h
@@ -0,0 +1,187 @@
+#ifndef LAKS_USB_USB_NRF_H
+#define LAKS_USB_USB_NRF_H
+
+#include "generic.h"
+#include "usb_nrf_def.h"
+
+#include <string.h>
+
+class USB_NRF : public USB_generic {
+ private:
+ USB_NRF_t& usb;
+
+ uint32_t ep_in_busy;
+
+ uint8_t buf_in[8][64];
+ uint8_t buf_out[8][64];
+
+ protected:
+ virtual void hw_set_address(uint8_t addr) {
+ usb_rblog.log("SetAddress: %d", addr);
+
+ // Do nothing, handled in hardware.
+ }
+
+ virtual void hw_conf_ep(uint8_t ep, EPType type, uint32_t size) {
+ usb_rblog.log("Configuring EP%02x: size=%d", ep, size);
+
+ uint8_t in = ep & 0x80;
+ ep &= 0x7f;
+
+ if(in || ep == 0) {
+ usb.reg_in[ep].PTR = (uint32_t)&buf_in[ep];
+ usb.reg.EPINEN |= 1 << ep;
+ }
+
+ if(!in) {
+ usb.reg_out[ep].PTR = (uint32_t)&buf_out[ep];
+
+ usb.reg.SIZE_EPOUT[ep] = 0;
+ usb.reg.EPOUTEN |= 1 << ep;
+ }
+ }
+
+ virtual void hw_set_stall(uint8_t ep) {
+ if(ep == 0) {
+ usb.tasks.EP0STALL = 1;
+ }
+ }
+
+ public:
+ USB_NRF(USB_NRF_t& usb_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), usb(usb_periph) {}
+
+ void init() {
+ *(volatile uint32_t*)0x4006ec00 = 0x00009375;
+ *(volatile uint32_t*)0x4006ed14 = 0x00000003;
+ *(volatile uint32_t*)0x4006ec00 = 0x00009375;
+
+ usb.reg.ENABLE = 1;
+
+ while(!(usb.reg.EVENTCAUSE & (1 << 11)));
+
+ usb.reg.EVENTCAUSE = 1 << 11;
+
+ *(volatile uint32_t*)0x4006ec00 = 0x00009375;
+ *(volatile uint32_t*)0x4006ed14 = 0x00000000;
+ *(volatile uint32_t*)0x4006ec00 = 0x00009375;
+
+ usb.reg.USBPULLUP = 1;
+ }
+
+ void process() {
+ if(usb.events.USBRESET) {
+ usb.events.USBRESET = 0;
+
+ usb_rblog.log("USB Reset");
+
+ handle_reset();
+ return;
+ }
+
+ if(usb.events.EP0SETUP) {
+ usb.events.EP0SETUP = 0;
+
+ uint8_t setupbuf[8] = {
+ (uint8_t)usb.reg.BMREQUESTTYPE,
+ (uint8_t)usb.reg.BREQUEST,
+ (uint8_t)usb.reg.WVALUEL,
+ (uint8_t)usb.reg.WVALUEH,
+ (uint8_t)usb.reg.WINDEXL,
+ (uint8_t)usb.reg.WINDEXH,
+ (uint8_t)usb.reg.WLENGTHL,
+ (uint8_t)usb.reg.WLENGTHH,
+ };
+
+ handle_setup((uint32_t*)&setupbuf);
+ }
+
+ if(usb.events.EP0DATADONE) {
+ // TODO: Support multi-packet data stages.
+ usb.events.EP0DATADONE = 0;
+
+ usb_rblog.log("Control data IN done, ACKing status stage.");
+
+ usb.tasks.EP0STATUS = 1;
+ }
+
+ /*
+ for(uint32_t ep = 0; ep <= 7; ep++) {
+ if(usb.events.ENDEPIN[ep]) {
+ usb.events.ENDEPIN[ep] = 0;
+
+ ep_in_busy &= ~(1 << ep);
+ }
+ }
+ */
+
+ if(usb.reg.EPDATASTATUS) {
+ for(uint32_t ep = 1; ep <= 7; ep++) {
+ if((usb.reg.EPDATASTATUS & ((1 << 16) << ep)) == 0) {
+ continue;
+ }
+
+ usb_rblog.log("EPDATA, starting DMA on ep %d", ep);
+
+ usb.reg.EPDATASTATUS = (1 << 16) << ep;
+
+ usb.reg_out[ep].MAXCNT = usb.reg.SIZE_EPOUT[ep];
+ usb.tasks.STARTEPOUT[ep] = 1;
+ }
+ }
+
+ for(uint32_t ep = 0; ep <= 7; ep++) {
+ if(usb.events.ENDEPOUT[ep]) {
+ usb.events.ENDEPOUT[ep] = 0;
+
+ handle_out(ep, usb.reg_out[ep].AMOUNT);
+ }
+ }
+ }
+
+ virtual bool ep_ready(uint32_t ep) {
+ //if(usb.events.ENDEPIN[ep]) {
+ // usb.events.ENDEPIN[ep] = 0;
+ // ep_in_busy &= ~(1 << ep);
+ //}
+
+ if(usb.reg.EPDATASTATUS & (1 << ep)) {
+ usb.reg.EPDATASTATUS = 1 << ep;
+
+ ep_in_busy &= ~(1 << ep);
+ }
+
+ return (ep_in_busy & (1 << ep)) == 0;
+ }
+
+ virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) {
+ usb_rblog.log("Writing, ep=%d, len=%d", ep, len);
+
+ if(ep == 0 && len == 0 && (usb.reg.BMREQUESTTYPE & 0x80) == 0) {
+ usb_rblog.log("EP0 status ACK");
+ usb.tasks.EP0STATUS = 1;
+ return;
+ }
+
+ memcpy(&buf_in[ep], bufp, len);
+
+ usb.reg_in[ep].MAXCNT = len;
+
+ usb.tasks.STARTEPIN[ep] = 1;
+
+ ep_in_busy |= 1 << ep;
+ }
+
+ virtual uint32_t read(uint32_t ep, uint32_t* bufp, uint32_t len) {
+ usb_rblog.log("Reading, ep=%d, len=%d", ep, len);
+
+ if(len > usb.reg_out[ep].AMOUNT) {
+ len = usb.reg_out[ep].AMOUNT;
+ }
+
+ memcpy(bufp, &buf_out[ep], len);
+
+ return len;
+ }
+};
+
+#endif
diff --git a/usb/usb_nrf_def.h b/usb/usb_nrf_def.h
new file mode 100644
index 0000000..0d56807
--- /dev/null
+++ b/usb/usb_nrf_def.h
@@ -0,0 +1,97 @@
+#ifndef LAKS_USB_USB_NRF_DEF_H
+#define LAKS_USB_USB_NRF_DEF_H
+
+#include <stdint.h>
+
+class USB_NRF_t {
+ private:
+ struct tasks_t {
+ uint32_t _reserved;
+ volatile uint32_t STARTEPIN[8];
+ volatile uint32_t STARTISOIN;
+ volatile uint32_t STARTEPOUT[8];
+ volatile uint32_t STARTISOOUT;
+ volatile uint32_t EP0RCVOUT;
+ volatile uint32_t EP0STATUS;
+ volatile uint32_t EP0STALL;
+ volatile uint32_t DPDMDRIVE;
+ volatile uint32_t DPDMNODRIVE;
+ };
+
+ struct events_t {
+ volatile uint32_t USBRESET;
+ volatile uint32_t STARTED;
+ volatile uint32_t ENDEPIN[8];
+ volatile uint32_t EP0DATADONE;
+ volatile uint32_t ENDISOIN;
+ volatile uint32_t ENDEPOUT[8];
+ volatile uint32_t ENDISOOUT;
+ volatile uint32_t SOF;
+ volatile uint32_t USBEVENT;
+ volatile uint32_t EP0SETUP;
+ volatile uint32_t EPDATA;
+ };
+
+ struct reg_t {
+ volatile uint32_t SHORTS;
+ uint32_t _reserved[63];
+ volatile uint32_t INTEN;
+ volatile uint32_t INTENSET;
+ volatile uint32_t INTENCLR;
+ uint32_t _reserved_1[61];
+ volatile uint32_t EVENTCAUSE;
+ uint32_t _reserved_2[7];
+ volatile uint32_t HALTED_EPIN[9];
+ volatile uint32_t HALTED_EPOUT[9];
+ volatile uint32_t EPSTATUS;
+ volatile uint32_t EPDATASTATUS;
+ volatile uint32_t USBADDR;
+ uint32_t _reserved_3[3];
+ volatile uint32_t BMREQUESTTYPE;
+ volatile uint32_t BREQUEST;
+ volatile uint32_t WVALUEL;
+ volatile uint32_t WVALUEH;
+ volatile uint32_t WINDEXL;
+ volatile uint32_t WINDEXH;
+ volatile uint32_t WLENGTHL;
+ volatile uint32_t WLENGTHH;
+ volatile uint32_t SIZE_EPOUT[8];
+ volatile uint32_t SIZE_ISOOUT;
+ uint32_t _reserved_4[15];
+ volatile uint32_t ENABLE;
+ volatile uint32_t USBPULLUP;
+ volatile uint32_t DPDMVALUE;
+ volatile uint32_t DTOGGLE;
+ volatile uint32_t EPINEN;
+ volatile uint32_t EPOUTEN;
+ volatile uint32_t EPSTALL;
+ volatile uint32_t ISOSPLIT;
+ volatile uint32_t FRAMECNTR;
+ uint32_t _reserved_5[2];
+ volatile uint32_t LOWPOWER;
+ volatile uint32_t ISOINCONFIG;
+ };
+
+ struct ep_reg_t {
+ volatile uint32_t PTR;
+ volatile uint32_t MAXCNT;
+ volatile uint32_t AMOUNT;
+ uint32_t _reserved[2];
+ };
+
+ public:
+ tasks_t& tasks;
+ events_t& events;
+ reg_t& reg;
+ ep_reg_t* reg_in;
+ ep_reg_t* reg_out;
+
+ USB_NRF_t(uint32_t reg_addr) :
+ tasks(*(tasks_t*)(reg_addr + 0x0)),
+ events(*(events_t*)(reg_addr + 0x100)),
+ reg(*(reg_t*)(reg_addr + 0x200)),
+ reg_in((ep_reg_t*)(reg_addr + 0x600)),
+ reg_out((ep_reg_t*)(reg_addr + 0x700)) {}
+};
+
+#endif