aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--os/hal/boards/FREESCALE_FREEDOM_K20D50M/board.h12
-rw-r--r--os/hal/boards/FREESCALE_FREEDOM_KL25Z/board.h16
-rw-r--r--os/hal/boards/FREESCALE_FREEDOM_KL26Z/board.h38
-rw-r--r--os/hal/boards/MCHCK_K20/board.h2
-rw-r--r--os/hal/boards/NRF51-DK/board.h57
-rw-r--r--os/hal/boards/PJRC_TEENSY_3/board.h37
-rw-r--r--os/hal/boards/PJRC_TEENSY_3_1/board.h37
-rw-r--r--os/hal/boards/PJRC_TEENSY_LC/board.h28
-rw-r--r--os/hal/boards/WVSHARE_BLE400/board.h42
-rw-r--r--os/hal/ports/KINETIS/LLD/hal_pal_lld.h37
-rw-r--r--os/hal/ports/MSP430X/hal_dma_lld.c253
-rw-r--r--os/hal/ports/MSP430X/hal_dma_lld.h67
-rw-r--r--os/hal/ports/MSP430X/hal_pal_lld.h51
-rw-r--r--os/hal/ports/MSP430X/hal_serial_lld.c483
-rw-r--r--os/hal/ports/MSP430X/hal_spi_lld.c578
-rw-r--r--os/hal/ports/MSP430X/hal_spi_lld.h642
-rw-r--r--os/hal/ports/MSP430X/platform.mk3
-rw-r--r--os/hal/ports/NRF51/NRF51822/hal_pal_lld.h63
-rw-r--r--os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c366
-rw-r--r--os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h276
-rw-r--r--os/hal/ports/NRF51/NRF51822/platform.mk6
-rw-r--r--testhal/KINETIS/FRDM-KL25Z/PWM/main.c10
-rw-r--r--testhal/KINETIS/FRDM-KL26Z/PWM/main.c16
-rw-r--r--testhal/KINETIS/MCHCK/PWM/main.c4
-rw-r--r--testhal/KINETIS/TEENSY_LC/PWM/main.c4
-rw-r--r--testhal/MSP430X/EXP430FR5969/DMA/Makefile1
-rw-r--r--testhal/MSP430X/EXP430FR5969/DMA/main.c198
-rw-r--r--testhal/MSP430X/EXP430FR5969/SPI/Makefile206
-rw-r--r--testhal/MSP430X/EXP430FR5969/SPI/chconf.h274
-rw-r--r--testhal/MSP430X/EXP430FR5969/SPI/halconf.h388
-rw-r--r--testhal/MSP430X/EXP430FR5969/SPI/main.c395
-rw-r--r--testhal/MSP430X/EXP430FR5969/SPI/mcuconf.h62
-rw-r--r--testhal/MSP430X/EXP430FR5969/SPI/msp_vectors.c316
-rw-r--r--testhal/NRF51/NRF51822/PWM/Makefile232
-rw-r--r--testhal/NRF51/NRF51822/PWM/chconf.h524
-rw-r--r--testhal/NRF51/NRF51822/PWM/halconf.h327
-rw-r--r--testhal/NRF51/NRF51822/PWM/main.c69
-rw-r--r--testhal/NRF51/NRF51822/PWM/mcuconf.h29
38 files changed, 5593 insertions, 556 deletions
diff --git a/os/hal/boards/FREESCALE_FREEDOM_K20D50M/board.h b/os/hal/boards/FREESCALE_FREEDOM_K20D50M/board.h
index cf41495..8f8605c 100644
--- a/os/hal/boards/FREESCALE_FREEDOM_K20D50M/board.h
+++ b/os/hal/boards/FREESCALE_FREEDOM_K20D50M/board.h
@@ -45,6 +45,18 @@
#define GPIO_LED_BLUE IOPORT1
#define PIN_LED_BLUE 2
+/* Inertial sensor: MMA8451Q */
+/* Default I2C address 0x1D */
+#define I2C_GYRO I2C0
+
+#define LINE_LED_RED PAL_LINE(GPIO_LED_RED, PIN_LED_RED)
+#define LINE_LED_GREEN PAL_LINE(GPIO_LED_GREEN, PIN_LED_GREEN)
+#define LINE_LED_BLUE PAL_LINE(GPIO_LED_BLUE, PIN_LED_BLUE)
+#define LINE_GYRO_SCL PAL_LINE(GPIOB, 0U)
+#define LINE_GYRO_SDA PAL_LINE(GPIOB, 1U)
+#define LINE_GYRO_INT1 PAL_LINE(GPIOC, 11U)
+#define LINE_GYRO_INT2 PAL_LINE(GPIOC, 6U)
+
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
diff --git a/os/hal/boards/FREESCALE_FREEDOM_KL25Z/board.h b/os/hal/boards/FREESCALE_FREEDOM_KL25Z/board.h
index 35d8e06..289ee91 100644
--- a/os/hal/boards/FREESCALE_FREEDOM_KL25Z/board.h
+++ b/os/hal/boards/FREESCALE_FREEDOM_KL25Z/board.h
@@ -45,7 +45,21 @@
#define GPIO_LED_BLUE IOPORT4
#define PIN_LED_BLUE 1
-#define I2C_INERIAL_SENSOR I2C0
+/* Inertial sensor: MMA8451Q */
+/* Default I2C address 0x1D */
+/* Note: the pins PTE24/25 are assigned to I2C0 by default;
+ * if I2C0 is wanted on other pins, these need to be
+ * assigned another function explicitly!
+ */
+#define I2C_GYRO I2C0
+
+#define LINE_LED_RED PAL_LINE(GPIO_LED_RED, PIN_LED_RED)
+#define LINE_LED_GREEN PAL_LINE(GPIO_LED_GREEN, PIN_LED_GREEN)
+#define LINE_LED_BLUE PAL_LINE(GPIO_LED_BLUE, PIN_LED_BLUE)
+#define LINE_GYRO_SCL PAL_LINE(GPIOE, 24U)
+#define LINE_GYRO_SDA PAL_LINE(GPIOE, 25U)
+#define LINE_GYRO_INT1 PAL_LINE(GPIOA, 14U)
+#define LINE_GYRO_INT2 PAL_LINE(GPIOA, 15U)
/*
* Not configured:
diff --git a/os/hal/boards/FREESCALE_FREEDOM_KL26Z/board.h b/os/hal/boards/FREESCALE_FREEDOM_KL26Z/board.h
index 2ae42aa..1db7947 100644
--- a/os/hal/boards/FREESCALE_FREEDOM_KL26Z/board.h
+++ b/os/hal/boards/FREESCALE_FREEDOM_KL26Z/board.h
@@ -38,16 +38,34 @@
/*
* Onboard features.
*/
-#define GPIO_LED_RED IOPORT5
-#define PIN_LED_RED 29
-#define GPIO_LED_GREEN IOPORT5
-#define PIN_LED_GREEN 31
-#define GPIO_LED_BLUE IOPORT4
-#define PIN_LED_BLUE 5
-#define GPIO_BUTTON IOPORT4
-#define PIN_BUTTON 0
-#define GPIO_LIGHTSNS IOPORT5
-#define PIN_LIGHTSNS 22
+#define GPIO_LED_RED IOPORT5
+#define PIN_LED_RED 29
+#define GPIO_LED_GREEN IOPORT5
+#define PIN_LED_GREEN 31
+#define GPIO_LED_BLUE IOPORT4
+#define PIN_LED_BLUE 5
+#define GPIO_BUTTON IOPORT4
+#define PIN_BUTTON 0
+#define GPIO_LIGHT_SENSOR IOPORT5
+#define PIN_LIGHT_SENSOR 22
+
+/* Inertial sensor: FXOS8700CQ */
+/* Default I2C address 0x1D */
+/* Note: the pins PTE24/25 are assigned to I2C0 by default;
+ * if I2C0 is wanted on other pins, these need to be
+ * assigned another function explicitly!
+ */
+#define I2C_GYRO I2C0
+
+#define LINE_LED_RED PAL_LINE(GPIO_LED_RED, PIN_LED_RED)
+#define LINE_LED_GREEN PAL_LINE(GPIO_LED_GREEN, PIN_LED_GREEN)
+#define LINE_LED_BLUE PAL_LINE(GPIO_LED_BLUE, PIN_LED_BLUE)
+#define LINE_BUTTON PAL_LINE(GPIO_BUTTON, PIN_BUTTON)
+#define LINE_LIGHT_SENSOR PAL_LINE(GPIO_LIGHT_SENSOR, PIN_LIGHT_SENSOR)
+#define LINE_GYRO_SCL PAL_LINE(GPIOE, 24U)
+#define LINE_GYRO_SDA PAL_LINE(GPIOE, 25U)
+#define LINE_GYRO_INT1 PAL_LINE(GPIOD, 0U)
+#define LINE_GYRO_INT2 PAL_LINE(GPIOD, 1U)
/*
* Not configured:
diff --git a/os/hal/boards/MCHCK_K20/board.h b/os/hal/boards/MCHCK_K20/board.h
index 504ab0e..aad3e27 100644
--- a/os/hal/boards/MCHCK_K20/board.h
+++ b/os/hal/boards/MCHCK_K20/board.h
@@ -34,6 +34,8 @@
#define GPIOB_LED 16
+#define LINE_LED PAL_LINE(GPIOB, GPIOB_LED)
+
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
diff --git a/os/hal/boards/NRF51-DK/board.h b/os/hal/boards/NRF51-DK/board.h
index 04c8daf..e47240b 100644
--- a/os/hal/boards/NRF51-DK/board.h
+++ b/os/hal/boards/NRF51-DK/board.h
@@ -45,6 +45,63 @@
#define I2C_SCL 7
#define I2C_SDA 30
+/*
+ * IO pins assignments.
+ */
+#define IOPORT1_BTN1 17U
+#define IOPORT1_BTN2 18U
+#define IOPORT1_BTN3 19U
+#define IOPORT1_BTN4 20U
+#define IOPORT1_LED1 21U
+#define IOPORT1_LED2 22U
+#define IOPORT1_LED3 23U
+#define IOPORT1_LED4 24U
+#define IOPORT1_UART_RTS 8U
+#define IOPORT1_UART_TX 9U
+#define IOPORT1_UART_CTS 10U
+#define IOPORT1_UART_RX 11U
+#define IOPORT1_SPI_SCK 29U
+#define IOPORT1_SPI_MOSI 25U
+#define IOPORT1_SPI_MISO 28U
+#define IOPORT1_SPI_SS 24U
+#define IOPORT1_I2C_SCL 7U
+#define IOPORT1_I2C_SDA 30U
+#define IOPORT1_A0 1U
+#define IOPORT1_A1 2U
+#define IOPORT1_A2 3U
+#define IOPORT1_A3 4U
+#define IOPORT1_A4 5U
+#define IOPORT1_A5 6U
+
+/*
+ * IO lines assignments.
+ */
+#define LINE_BTN1 PAL_LINE(IOPORT1, IOPORT1_BTN1)
+#define LINE_BTN2 PAL_LINE(IOPORT1, IOPORT1_BTN2)
+#define LINE_BTN3 PAL_LINE(IOPORT1, IOPORT1_BTN3)
+#define LINE_BTN4 PAL_LINE(IOPORT1, IOPORT1_BTN4)
+#define LINE_LED1 PAL_LINE(IOPORT1, IOPORT1_LED1)
+#define LINE_LED2 PAL_LINE(IOPORT1, IOPORT1_LED2)
+#define LINE_LED3 PAL_LINE(IOPORT1, IOPORT1_LED3)
+#define LINE_LED4 PAL_LINE(IOPORT1, IOPORT1_LED4)
+#define LINE_UART_RTS PAL_LINE(IOPORT1, IOPORT1_UART_RTS)
+#define LINE_UART_TX PAL_LINE(IOPORT1, IOPORT1_UART_TX)
+#define LINE_UART_CTS PAL_LINE(IOPORT1, IOPORT1_UART_CTS)
+#define LINE_UART_RX PAL_LINE(IOPORT1, IOPORT1_UART_RX)
+#define LINE_SPI_SCK PAL_LINE(IOPORT1, IOPORT1_SPI_SCK)
+#define LINE_SPI_MOSI PAL_LINE(IOPORT1, IOPORT1_SPI_MOSI)
+#define LINE_SPI_MISO PAL_LINE(IOPORT1, IOPORT1_SPI_MISO)
+#define LINE_SPI_SS PAL_LINE(IOPORT1, IOPORT1_SPI_SS)
+#define LINE_I2C_SCL PAL_LINE(IOPORT1, IOPORT1_I2C_SCL)
+#define LINE_I2C_SDA PAL_LINE(IOPORT1, IOPORT1_I2C_SDA)
+#define LINE_A0 PAL_LINE(IOPORT1, IOPORT1_A0)
+#define LINE_A1 PAL_LINE(IOPORT1, IOPORT1_A1)
+#define LINE_A2 PAL_LINE(IOPORT1, IOPORT1_A2)
+#define LINE_A3 PAL_LINE(IOPORT1, IOPORT1_A3)
+#define LINE_A4 PAL_LINE(IOPORT1, IOPORT1_A4)
+#define LINE_A5 PAL_LINE(IOPORT1, IOPORT1_A5)
+
+
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
diff --git a/os/hal/boards/PJRC_TEENSY_3/board.h b/os/hal/boards/PJRC_TEENSY_3/board.h
index ee9f514..f3e7383 100644
--- a/os/hal/boards/PJRC_TEENSY_3/board.h
+++ b/os/hal/boards/PJRC_TEENSY_3/board.h
@@ -245,6 +245,43 @@
#define TEENSY_PIN26_IOPORT IOPORT5
#define TEENSY_PIN31_IOPORT IOPORT5
+#define LINE_PIN1 PAL_LINE(TEENSY_PIN1_IOPORT, TEENSY_PIN1)
+#define LINE_PIN2 PAL_LINE(TEENSY_PIN2_IOPORT, TEENSY_PIN2)
+#define LINE_PIN3 PAL_LINE(TEENSY_PIN3_IOPORT, TEENSY_PIN3)
+#define LINE_PIN4 PAL_LINE(TEENSY_PIN4_IOPORT, TEENSY_PIN4)
+#define LINE_PIN5 PAL_LINE(TEENSY_PIN5_IOPORT, TEENSY_PIN5)
+#define LINE_PIN6 PAL_LINE(TEENSY_PIN6_IOPORT, TEENSY_PIN6)
+#define LINE_PIN7 PAL_LINE(TEENSY_PIN7_IOPORT, TEENSY_PIN7)
+#define LINE_PIN8 PAL_LINE(TEENSY_PIN8_IOPORT, TEENSY_PIN8)
+#define LINE_PIN9 PAL_LINE(TEENSY_PIN9_IOPORT, TEENSY_PIN9)
+#define LINE_PIN10 PAL_LINE(TEENSY_PIN10_IOPORT, TEENSY_PIN10)
+#define LINE_PIN11 PAL_LINE(TEENSY_PIN11_IOPORT, TEENSY_PIN11)
+#define LINE_PIN12 PAL_LINE(TEENSY_PIN12_IOPORT, TEENSY_PIN12)
+#define LINE_PIN13 PAL_LINE(TEENSY_PIN13_IOPORT, TEENSY_PIN13)
+#define LINE_PIN14 PAL_LINE(TEENSY_PIN14_IOPORT, TEENSY_PIN14)
+#define LINE_PIN15 PAL_LINE(TEENSY_PIN15_IOPORT, TEENSY_PIN15)
+#define LINE_PIN16 PAL_LINE(TEENSY_PIN16_IOPORT, TEENSY_PIN16)
+#define LINE_PIN17 PAL_LINE(TEENSY_PIN17_IOPORT, TEENSY_PIN17)
+#define LINE_PIN18 PAL_LINE(TEENSY_PIN18_IOPORT, TEENSY_PIN18)
+#define LINE_PIN19 PAL_LINE(TEENSY_PIN19_IOPORT, TEENSY_PIN19)
+#define LINE_PIN20 PAL_LINE(TEENSY_PIN20_IOPORT, TEENSY_PIN20)
+#define LINE_PIN21 PAL_LINE(TEENSY_PIN21_IOPORT, TEENSY_PIN21)
+#define LINE_PIN22 PAL_LINE(TEENSY_PIN22_IOPORT, TEENSY_PIN22)
+#define LINE_PIN23 PAL_LINE(TEENSY_PIN23_IOPORT, TEENSY_PIN23)
+#define LINE_PIN24 PAL_LINE(TEENSY_PIN24_IOPORT, TEENSY_PIN24)
+#define LINE_PIN25 PAL_LINE(TEENSY_PIN25_IOPORT, TEENSY_PIN25)
+#define LINE_PIN25 PAL_LINE(TEENSY_PIN25_IOPORT, TEENSY_PIN25)
+#define LINE_PIN26 PAL_LINE(TEENSY_PIN26_IOPORT, TEENSY_PIN26)
+#define LINE_PIN27 PAL_LINE(TEENSY_PIN27_IOPORT, TEENSY_PIN27)
+#define LINE_PIN28 PAL_LINE(TEENSY_PIN28_IOPORT, TEENSY_PIN28)
+#define LINE_PIN29 PAL_LINE(TEENSY_PIN29_IOPORT, TEENSY_PIN29)
+#define LINE_PIN30 PAL_LINE(TEENSY_PIN30_IOPORT, TEENSY_PIN30)
+#define LINE_PIN31 PAL_LINE(TEENSY_PIN31_IOPORT, TEENSY_PIN31)
+#define LINE_PIN32 PAL_LINE(TEENSY_PIN32_IOPORT, TEENSY_PIN32)
+#define LINE_PIN33 PAL_LINE(TEENSY_PIN33_IOPORT, TEENSY_PIN33)
+
+#define LINE_LED LINE_PIN13
+
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
diff --git a/os/hal/boards/PJRC_TEENSY_3_1/board.h b/os/hal/boards/PJRC_TEENSY_3_1/board.h
index 6e89c07..76a52b7 100644
--- a/os/hal/boards/PJRC_TEENSY_3_1/board.h
+++ b/os/hal/boards/PJRC_TEENSY_3_1/board.h
@@ -245,6 +245,43 @@
#define TEENSY_PIN26_IOPORT IOPORT5
#define TEENSY_PIN31_IOPORT IOPORT5
+#define LINE_PIN1 PAL_LINE(TEENSY_PIN1_IOPORT, TEENSY_PIN1)
+#define LINE_PIN2 PAL_LINE(TEENSY_PIN2_IOPORT, TEENSY_PIN2)
+#define LINE_PIN3 PAL_LINE(TEENSY_PIN3_IOPORT, TEENSY_PIN3)
+#define LINE_PIN4 PAL_LINE(TEENSY_PIN4_IOPORT, TEENSY_PIN4)
+#define LINE_PIN5 PAL_LINE(TEENSY_PIN5_IOPORT, TEENSY_PIN5)
+#define LINE_PIN6 PAL_LINE(TEENSY_PIN6_IOPORT, TEENSY_PIN6)
+#define LINE_PIN7 PAL_LINE(TEENSY_PIN7_IOPORT, TEENSY_PIN7)
+#define LINE_PIN8 PAL_LINE(TEENSY_PIN8_IOPORT, TEENSY_PIN8)
+#define LINE_PIN9 PAL_LINE(TEENSY_PIN9_IOPORT, TEENSY_PIN9)
+#define LINE_PIN10 PAL_LINE(TEENSY_PIN10_IOPORT, TEENSY_PIN10)
+#define LINE_PIN11 PAL_LINE(TEENSY_PIN11_IOPORT, TEENSY_PIN11)
+#define LINE_PIN12 PAL_LINE(TEENSY_PIN12_IOPORT, TEENSY_PIN12)
+#define LINE_PIN13 PAL_LINE(TEENSY_PIN13_IOPORT, TEENSY_PIN13)
+#define LINE_PIN14 PAL_LINE(TEENSY_PIN14_IOPORT, TEENSY_PIN14)
+#define LINE_PIN15 PAL_LINE(TEENSY_PIN15_IOPORT, TEENSY_PIN15)
+#define LINE_PIN16 PAL_LINE(TEENSY_PIN16_IOPORT, TEENSY_PIN16)
+#define LINE_PIN17 PAL_LINE(TEENSY_PIN17_IOPORT, TEENSY_PIN17)
+#define LINE_PIN18 PAL_LINE(TEENSY_PIN18_IOPORT, TEENSY_PIN18)
+#define LINE_PIN19 PAL_LINE(TEENSY_PIN19_IOPORT, TEENSY_PIN19)
+#define LINE_PIN20 PAL_LINE(TEENSY_PIN20_IOPORT, TEENSY_PIN20)
+#define LINE_PIN21 PAL_LINE(TEENSY_PIN21_IOPORT, TEENSY_PIN21)
+#define LINE_PIN22 PAL_LINE(TEENSY_PIN22_IOPORT, TEENSY_PIN22)
+#define LINE_PIN23 PAL_LINE(TEENSY_PIN23_IOPORT, TEENSY_PIN23)
+#define LINE_PIN24 PAL_LINE(TEENSY_PIN24_IOPORT, TEENSY_PIN24)
+#define LINE_PIN25 PAL_LINE(TEENSY_PIN25_IOPORT, TEENSY_PIN25)
+#define LINE_PIN25 PAL_LINE(TEENSY_PIN25_IOPORT, TEENSY_PIN25)
+#define LINE_PIN26 PAL_LINE(TEENSY_PIN26_IOPORT, TEENSY_PIN26)
+#define LINE_PIN27 PAL_LINE(TEENSY_PIN27_IOPORT, TEENSY_PIN27)
+#define LINE_PIN28 PAL_LINE(TEENSY_PIN28_IOPORT, TEENSY_PIN28)
+#define LINE_PIN29 PAL_LINE(TEENSY_PIN29_IOPORT, TEENSY_PIN29)
+#define LINE_PIN30 PAL_LINE(TEENSY_PIN30_IOPORT, TEENSY_PIN30)
+#define LINE_PIN31 PAL_LINE(TEENSY_PIN31_IOPORT, TEENSY_PIN31)
+#define LINE_PIN32 PAL_LINE(TEENSY_PIN32_IOPORT, TEENSY_PIN32)
+#define LINE_PIN33 PAL_LINE(TEENSY_PIN33_IOPORT, TEENSY_PIN33)
+
+#define LINE_LED LINE_PIN13
+
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
diff --git a/os/hal/boards/PJRC_TEENSY_LC/board.h b/os/hal/boards/PJRC_TEENSY_LC/board.h
index 3f181f8..ad75343 100644
--- a/os/hal/boards/PJRC_TEENSY_LC/board.h
+++ b/os/hal/boards/PJRC_TEENSY_LC/board.h
@@ -238,6 +238,34 @@
#define TEENSY_PIN25_IOPORT IOPORT5
#define TEENSY_PIN26_IOPORT IOPORT5
+#define LINE_PIN1 PAL_LINE(TEENSY_PIN1_IOPORT, TEENSY_PIN1)
+#define LINE_PIN2 PAL_LINE(TEENSY_PIN2_IOPORT, TEENSY_PIN2)
+#define LINE_PIN3 PAL_LINE(TEENSY_PIN3_IOPORT, TEENSY_PIN3)
+#define LINE_PIN4 PAL_LINE(TEENSY_PIN4_IOPORT, TEENSY_PIN4)
+#define LINE_PIN5 PAL_LINE(TEENSY_PIN5_IOPORT, TEENSY_PIN5)
+#define LINE_PIN6 PAL_LINE(TEENSY_PIN6_IOPORT, TEENSY_PIN6)
+#define LINE_PIN7 PAL_LINE(TEENSY_PIN7_IOPORT, TEENSY_PIN7)
+#define LINE_PIN8 PAL_LINE(TEENSY_PIN8_IOPORT, TEENSY_PIN8)
+#define LINE_PIN9 PAL_LINE(TEENSY_PIN9_IOPORT, TEENSY_PIN9)
+#define LINE_PIN10 PAL_LINE(TEENSY_PIN10_IOPORT, TEENSY_PIN10)
+#define LINE_PIN11 PAL_LINE(TEENSY_PIN11_IOPORT, TEENSY_PIN11)
+#define LINE_PIN12 PAL_LINE(TEENSY_PIN12_IOPORT, TEENSY_PIN12)
+#define LINE_PIN13 PAL_LINE(TEENSY_PIN13_IOPORT, TEENSY_PIN13)
+#define LINE_PIN14 PAL_LINE(TEENSY_PIN14_IOPORT, TEENSY_PIN14)
+#define LINE_PIN15 PAL_LINE(TEENSY_PIN15_IOPORT, TEENSY_PIN15)
+#define LINE_PIN16 PAL_LINE(TEENSY_PIN16_IOPORT, TEENSY_PIN16)
+#define LINE_PIN17 PAL_LINE(TEENSY_PIN17_IOPORT, TEENSY_PIN17)
+#define LINE_PIN18 PAL_LINE(TEENSY_PIN18_IOPORT, TEENSY_PIN18)
+#define LINE_PIN19 PAL_LINE(TEENSY_PIN19_IOPORT, TEENSY_PIN19)
+#define LINE_PIN20 PAL_LINE(TEENSY_PIN20_IOPORT, TEENSY_PIN20)
+#define LINE_PIN21 PAL_LINE(TEENSY_PIN21_IOPORT, TEENSY_PIN21)
+#define LINE_PIN22 PAL_LINE(TEENSY_PIN22_IOPORT, TEENSY_PIN22)
+#define LINE_PIN23 PAL_LINE(TEENSY_PIN23_IOPORT, TEENSY_PIN23)
+#define LINE_PIN24 PAL_LINE(TEENSY_PIN24_IOPORT, TEENSY_PIN24)
+#define LINE_PIN25 PAL_LINE(TEENSY_PIN25_IOPORT, TEENSY_PIN25)
+
+#define LINE_LED LINE_PIN13
+
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
diff --git a/os/hal/boards/WVSHARE_BLE400/board.h b/os/hal/boards/WVSHARE_BLE400/board.h
index 617a0b5..fd52467 100644
--- a/os/hal/boards/WVSHARE_BLE400/board.h
+++ b/os/hal/boards/WVSHARE_BLE400/board.h
@@ -43,6 +43,48 @@
#define I2C_SCL 1
#define I2C_SDA 0
+/*
+ * IO pins assignments.
+ */
+#define IOPORT1_KEY1 16U
+#define IOPORT1_KEY2 17U
+#define IOPORT1_LED0 18U
+#define IOPORT1_LED1 19U
+#define IOPORT1_LED2 20U
+#define IOPORT1_LED3 21U
+#define IOPORT1_LED4 22U
+#define IOPORT1_UART_TX 9U
+#define IOPORT1_UART_RX 11U
+#define IOPORT1_UART_RTS 8U
+#define IOPORT1_UART_CTS 10U
+#define IOPORT1_SPI_SCK 25U
+#define IOPORT1_SPI_MOSI 24U
+#define IOPORT1_SPI_MISO 23U
+#define IOPORT1_SPI_SS 30U
+#define IOPORT1_I2C_SCL 1U
+#define IOPORT1_I2C_SDA 0U
+
+/*
+ * IO lines assignments.
+ */
+#define LINE_KEY1 PAL_LINE(IOPORT1, IOPORT1_KEY1)
+#define LINE_KEY2 PAL_LINE(IOPORT1, IOPORT1_KEY2)
+#define LINE_LED0 PAL_LINE(IOPORT1, IOPORT1_LED0)
+#define LINE_LED1 PAL_LINE(IOPORT1, IOPORT1_LED1)
+#define LINE_LED2 PAL_LINE(IOPORT1, IOPORT1_LED2)
+#define LINE_LED3 PAL_LINE(IOPORT1, IOPORT1_LED3)
+#define LINE_LED4 PAL_LINE(IOPORT1, IOPORT1_LED4)
+#define LINE_UART_TX PAL_LINE(IOPORT1, IOPORT1_UART_TX)
+#define LINE_UART_RX PAL_LINE(IOPORT1, IOPORT1_UART_RX)
+#define LINE_UART_RTS PAL_LINE(IOPORT1, IOPORT1_UART_RTS)
+#define LINE_UART_CTS PAL_LINE(IOPORT1, IOPORT1_UART_CTS)
+#define LINE_SPI_SCK PAL_LINE(IOPORT1, IOPORT1_SPI_SCK)
+#define LINE_SPI_MOSI PAL_LINE(IOPORT1, IOPORT1_SPI_MOSI)
+#define LINE_SPI_MISO PAL_LINE(IOPORT1, IOPORT1_SPI_MISO)
+#define LINE_SPI_SS PAL_LINE(IOPORT1, IOPORT1_SPI_SS)
+#define LINE_I2C_SCL PAL_LINE(IOPORT1, IOPORT1_I2C_SCL)
+#define LINE_I2C_SDA PAL_LINE(IOPORT1, IOPORT1_I2C_SDA)
+
#if !defined(_FROM_ASM_)
#ifdef __cplusplus
extern "C" {
diff --git a/os/hal/ports/KINETIS/LLD/hal_pal_lld.h b/os/hal/ports/KINETIS/LLD/hal_pal_lld.h
index 05749d5..833d95e 100644
--- a/os/hal/ports/KINETIS/LLD/hal_pal_lld.h
+++ b/os/hal/ports/KINETIS/LLD/hal_pal_lld.h
@@ -70,6 +70,11 @@ typedef uint32_t ioportmask_t;
typedef uint32_t iomode_t;
/**
+ * @brief Type of an I/O line.
+ */
+typedef uint32_t ioline_t;
+
+/**
* @brief Port Identifier.
* @details This type can be a scalar or some kind of pointer, do not make
* any assumption about it, use the provided macros when populating
@@ -129,6 +134,38 @@ typedef struct {
*/
#define IOPORT5 GPIOE
+/**
+ * @name Line handling macros
+ * @{
+ */
+/**
+ * @brief Forms a line identifier.
+ * @details A port/pad pair are encoded into an @p ioline_t type. The encoding
+ * of this type is platform-dependent.
+ * @note In this driver the pad number is encoded in the byte of the GPIO
+ * address that's zero on all Kinetis devices.
+ */
+#define PAL_LINE(port, pad) \
+ ((ioline_t)((uint32_t)(port) | ((uint32_t)(pad)<<20)))
+
+/**
+ * @brief Decodes a port identifier from a line identifier.
+ */
+#define PAL_PORT(line) \
+ ((GPIO_TypeDef *)(((uint32_t)(line)) & 0xF00FFFFFU))
+
+/**
+ * @brief Decodes a pad identifier from a line identifier.
+ */
+#define PAL_PAD(line) \
+ ((uint32_t)((uint32_t)(line) & 0x0FF00000U)>>20)
+
+/**
+ * @brief Value identifying an invalid line.
+ */
+#define PAL_NOLINE 0U
+/** @} */
+
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* functions, if so please put them in pal_lld.c. */
diff --git a/os/hal/ports/MSP430X/hal_dma_lld.c b/os/hal/ports/MSP430X/hal_dma_lld.c
index 58293ca..43e1d6c 100644
--- a/os/hal/ports/MSP430X/hal_dma_lld.c
+++ b/os/hal/ports/MSP430X/hal_dma_lld.c
@@ -40,9 +40,8 @@
/* Driver local variables and types. */
/*===========================================================================*/
-/* TODO make sure this is right... */
-static msp430x_dma_ch_reg_t * const dma_channels = (msp430x_dma_ch_reg_t *)&DMA0CTL;
-static uint8_t * const dma_ctls = (uint8_t *)&DMACTL0;
+static msp430x_dma_ch_reg_t * const dma_channels =
+ (msp430x_dma_ch_reg_t *)&DMA0CTL;
static msp430x_dma_cb_t callbacks[MSP430X_DMA_CHANNELS];
#if CH_CFG_USE_SEMAPHORES
@@ -53,16 +52,29 @@ static semaphore_t dma_lock;
/* Driver local functions. */
/*===========================================================================*/
+/**
+ * @brief Set a DMA trigger using an index.
+ *
+ * @param[in] index The index of the DMA channel whose trigger is set.
+ * @param[in] trigger The trigger to use.
+ * @note This is all to get around weird MSP behavior when writing to memory-
+ * mapped registers using bytewise instructions.
+ */
+static void dma_trigger_set(uint8_t index, uint8_t trigger) {
+ uint16_t * ctl = ((uint16_t *)((uintptr_t)(&DMACTL0)) + (index / 2));
+ *ctl &= 0xFF00 >> (8 * (index % 2));
+ *ctl |= trigger << (8 * (index % 2));
+}
static void init_request(const msp430x_dma_req_t * request, uint8_t index) {
-
- dma_ctls[index] = request->trigger;
- callbacks[index] = request->callback;
- msp430x_dma_ch_reg_t * ch = &dma_channels[index];
- ch->sa = (uintptr_t)request->source_addr;
- ch->da = (uintptr_t)request->dest_addr;
- ch->sz = request->size;
- ch->ctl = DMAREQ | DMAIE | DMAEN | request->data_mode | request->addr_mode
- | request->transfer_mode;
+
+ dma_trigger_set(index, request->trigger);
+ callbacks[index] = request->callback;
+ msp430x_dma_ch_reg_t * ch = &dma_channels[index];
+ ch->sa = (uintptr_t)request->source_addr;
+ ch->da = (uintptr_t)request->dest_addr;
+ ch->sz = request->size;
+ ch->ctl = DMAREQ | DMAIE | DMAEN | request->data_mode | request->addr_mode |
+ request->transfer_mode;
}
/*===========================================================================*/
@@ -72,19 +84,22 @@ static void init_request(const msp430x_dma_req_t * request, uint8_t index) {
PORT_IRQ_HANDLER(DMA_VECTOR) {
uint8_t index;
OSAL_IRQ_PROLOGUE();
-
+
index = (DMAIV >> 1) - 1;
-
+
if (index < MSP430X_DMA_CHANNELS) {
+#if CH_CFG_USE_SEMAPHORES
+ chSemSignalI(&dma_lock);
+#endif
+
msp430x_dma_cb_t * cb = &callbacks[index];
-
+
/* WARNING: CALLBACKS ARE CALLED IN AN ISR CONTEXT! */
if (cb->callback != NULL) {
cb->callback(cb->args);
}
-
- }
-
+ }
+
OSAL_IRQ_EPILOGUE();
}
@@ -94,7 +109,7 @@ PORT_IRQ_HANDLER(DMA_VECTOR) {
/**
* @brief Initialize the DMA engine.
- *
+ *
* @init
*/
void dmaInit(void) {
@@ -112,132 +127,132 @@ void dmaInit(void) {
* disabled, the calling thread will busy-wait instead of sleeping.
*/
bool dmaRequest(msp430x_dma_req_t * request, systime_t timeout) {
- /* Check if a DMA channel is available */
+/* Check if a DMA channel is available */
#if CH_CFG_USE_SEMAPHORES
msg_t semresult = chSemWaitTimeout(&dma_lock, timeout);
if (semresult != MSG_OK)
return true;
#endif
-
+
#if !(CH_CFG_USE_SEMAPHORES)
systime_t start = chVTGetSystemTimeX();
-
+
do {
#endif
- /* Grab the correct DMA channel to use */
- int i = 0;
- for (i = 0; i < MSP430X_DMA_CHANNELS; i++) {
- if (!(dma_channels[i].ctl & DMAEN)) {
- break;
+ /* Grab the correct DMA channel to use */
+ int i = 0;
+ for (i = 0; i < MSP430X_DMA_CHANNELS; i++) {
+ if (!(dma_channels[i].ctl & DMAEN)) {
+ break;
+ }
}
- }
#if !(CH_CFG_USE_SEMAPHORES)
- while (chVTTimeElapsedSinceX(start) < timeout);
+ while (chVTTimeElapsedSinceX(start) < timeout)
+ ;
#endif
-
+
#if !(CH_CFG_USE_SEMAPHORES)
- if (i == MSP430X_DMA_CHANNELS) {
- return true;
- }
-#endif
-
- /* Make the request */
- init_request(request, i);
-
-#if CH_CFG_USE_SEMAPHORES
- chSemSignal(&dma_lock);
+ if (i == MSP430X_DMA_CHANNELS) {
+ return true;
+ }
#endif
-
- return false;
-}
-/**
- * @brief Acquires exclusive control of a DMA channel.
- * @pre The channel must not be already acquired or an error is returned.
- * @note If the channel is in use by the DMA engine, blocks until acquired.
- * @post This channel must be interacted with using only the functions
- * defined in this module.
- *
- * @param[out] channel The channel handle. Must be pre-allocated.
- * @param[in] index The index of the channel (< MSP430X_DMA_CHANNELS).
- * @return The operation status.
- * @retval false no error, channel acquired.
- * @retval true error, channel already acquired.
- */
-bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index) {
- /* Acquire the channel in an idle mode */
-
- /* Is the channel already acquired? */
- osalDbgAssert(index < MSP430X_DMA_CHANNELS, "invalid channel index");
- if (dma_channels[index].ctl & DMADT_4) {
- return true;
+ /* Make the request */
+ init_request(request, i);
+
+ return false;
}
-
- /* Increment the DMA counter */
+
+ /**
+ * @brief Acquires exclusive control of a DMA channel.
+ * @pre The channel must not be already acquired or an error is returned.
+ * @note If the channel is in use by the DMA engine, blocks until acquired.
+ * @post This channel must be interacted with using only the functions
+ * defined in this module.
+ *
+ * @param[out] channel The channel handle. Must be pre-allocated.
+ * @param[in] index The index of the channel (< MSP430X_DMA_CHANNELS).
+ * @return The operation status.
+ * @retval false no error, channel acquired.
+ * @retval true error, channel already acquired.
+ */
+ bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index) {
+ /* Acquire the channel in an idle mode */
+
+ /* Is the channel already acquired? */
+ osalDbgAssert(index < MSP430X_DMA_CHANNELS, "invalid channel index");
+ if (dma_channels[index].ctl & DMADT_4) {
+ return true;
+ }
+
+/* Increment the DMA counter */
#if CH_CFG_USE_SEMAPHORES
- msg_t semresult = chSemWait(&dma_lock);
- if (semresult != MSG_OK)
- return true;
+ msg_t semresult = chSemWait(&dma_lock);
+ if (semresult != MSG_OK)
+ return true;
#endif
-
- while (dma_channels[index].ctl & DMAEN) ;
-
- dma_ctls[index] = DMA_TRIGGER_MNEM(DMAREQ);
- dma_channels[index].sz = 0;
- dma_channels[index].ctl = DMAEN | DMAABORT | DMADT_4;
-
- channel->registers = dma_channels + index;
- channel->ctl = dma_ctls + index;
- channel->cb = callbacks + index;
-
- return false;
-}
-/**
- * @brief Initiates a DMA transfer operation using an acquired channel.
- * @pre The channel must have been acquired using @p dmaAcquire().
- *
- * @param[in] channel pointer to a DMA channel from @p dmaAcquire().
- * @param[in] request pointer to a DMA request object.
- */
-void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request) {
-
- *(channel->ctl) = request->trigger;
-
+ while (dma_channels[index].ctl & DMAEN)
+ ;
+
+ dma_trigger_set(index, DMA_TRIGGER_MNEM(DMAREQ));
+ dma_channels[index].sz = 0;
+ dma_channels[index].ctl = DMAEN | DMAABORT | DMADT_4;
+
+ channel->registers = dma_channels + index;
+ channel->index = index;
+ channel->cb = callbacks + index;
+
+ return false;
+ }
+
+ /**
+ * @brief Initiates a DMA transfer operation using an acquired channel.
+ * @pre The channel must have been acquired using @p dmaAcquire().
+ *
+ * @param[in] channel pointer to a DMA channel from @p dmaAcquire().
+ * @param[in] request pointer to a DMA request object.
+ */
+ void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request) {
+
+ dma_trigger_set(channel->index, request->trigger);
+ /**(channel->ctl) = request->trigger;*/
+
channel->cb->callback = request->callback.callback;
- channel->cb->args = request->callback.args;
-
+ channel->cb->args = request->callback.args;
+
chSysLock();
channel->registers->ctl &= (~DMAEN);
- channel->registers->sa = (uintptr_t)request->source_addr;
- channel->registers->da = (uintptr_t)request->dest_addr;
- channel->registers->sz = request->size;
- channel->registers->ctl = DMAIE | request->data_mode | request->addr_mode
- | request->transfer_mode | DMADT_4 | DMAEN | DMAREQ; /* repeated transfers */
+ channel->registers->sa = (uintptr_t)request->source_addr;
+ channel->registers->da = (uintptr_t)request->dest_addr;
+ channel->registers->sz = request->size;
+ channel->registers->ctl = DMAIE | request->data_mode | request->addr_mode |
+ request->transfer_mode | DMADT_4 | DMAEN |
+ DMAREQ; /* repeated transfers */
chSysUnlock();
-}
+ }
-/**
- * @brief Releases exclusive control of a DMA channel.
- * @details The channel is released from control and returned to the DMA engine
- * pool. Trying to release an unallocated channel is an illegal
- * operation and is trapped if assertions are enabled.
- * @pre The channel must have been acquired using @p dmaAcquire().
- * @post The channel is returned to the DMA engine pool.
- */
-void dmaRelease(msp430x_dma_ch_t * channel) {
-
- osalDbgCheck(channel != NULL);
- osalDbgAssert(channel->registers->ctl & DMADT_4, "not acquired");
-
- /* Release the channel in an idle mode */
- channel->registers->ctl = DMAABORT;
-
- /* release the DMA counter */
+ /**
+ * @brief Releases exclusive control of a DMA channel.
+ * @details The channel is released from control and returned to the DMA
+ * engine
+ * pool. Trying to release an unallocated channel is an illegal
+ * operation and is trapped if assertions are enabled.
+ * @pre The channel must have been acquired using @p dmaAcquire().
+ * @post The channel is returned to the DMA engine pool.
+ */
+ void dmaRelease(msp430x_dma_ch_t * channel) {
+
+ osalDbgCheck(channel != NULL);
+
+ /* Release the channel in an idle mode */
+ channel->registers->ctl = DMAABORT;
+
+/* release the DMA counter */
#if CH_CFG_USE_SEMAPHORES
- chSemSignal(&dma_lock);
+ chSemSignal(&dma_lock);
#endif
-}
+ }
#endif /* HAL_USE_DMA == TRUE */
diff --git a/os/hal/ports/MSP430X/hal_dma_lld.h b/os/hal/ports/MSP430X/hal_dma_lld.h
index 2cce85d..d1495d2 100644
--- a/os/hal/ports/MSP430X/hal_dma_lld.h
+++ b/os/hal/ports/MSP430X/hal_dma_lld.h
@@ -34,18 +34,18 @@
/*===========================================================================*/
#define MSP430X_DMA_SINGLE DMADT_0
-#define MSP430X_DMA_BLOCK DMADT_1
-#define MSP430X_DMA_BURST DMADT_2
+#define MSP430X_DMA_BLOCK DMADT_1
+#define MSP430X_DMA_BURST DMADT_2
-#define MSP430X_DMA_SRCINCR DMASRCINCR_3
-#define MSP430X_DMA_SRCDECR DMASRCINCR_2
-#define MSP430X_DMA_DSTINCR DMADSTINCR_3
-#define MSP430X_DMA_DSTDECR DMADSTINCR_2
+#define MSP430X_DMA_SRCINCR DMASRCINCR_3
+#define MSP430X_DMA_SRCDECR DMASRCINCR_2
+#define MSP430X_DMA_DSTINCR DMADSTINCR_3
+#define MSP430X_DMA_DSTDECR DMADSTINCR_2
-#define MSP430X_DMA_SRCBYTE DMASRCBYTE
-#define MSP430X_DMA_DSTBYTE DMADSTBYTE
-#define MSP430X_DMA_SRCWORD 0
-#define MSP430X_DMA_DSTWORD 0
+#define MSP430X_DMA_SRCBYTE DMASRCBYTE
+#define MSP430X_DMA_DSTBYTE DMADSTBYTE
+#define MSP430X_DMA_SRCWORD 0
+#define MSP430X_DMA_DSTWORD 0
/*===========================================================================*/
/* Driver pre-compile time settings. */
@@ -56,8 +56,8 @@
/*===========================================================================*/
#if !defined(DMA_BASE) && !defined(MSP430X_DMA_SOFTWARE)
- #error "The MSP430 device in use does not support DMA. Explicitly enable"
- #error "software support by defining MSP430X_DMA_SOFTWARE."
+#error "The MSP430 device in use does not support DMA. Explicitly enable"
+#error "software emulation by defining MSP430X_DMA_SOFTWARE."
#endif
#if defined(__MSP430_HAS_DMAX_1__) || defined(__MSP430X_HAS_DMA_1__)
@@ -67,7 +67,7 @@
#elif defined(__MSP430_HAS_DMAX_6__) || defined(__MSP430X_HAS_DMA_6__)
#define MSP430X_DMA_CHANNELS 6
#else
- #error "Unexpected error - how many DMA channels does your MSP have?"
+#error "Unexpected error - how many DMA channels does your MSP have?"
#endif
/*===========================================================================*/
@@ -77,28 +77,28 @@
/**
* @brief Type of DMA callback function pointer.
*/
-typedef void (*msp430x_dma_cbp_t)(void *args);
+typedef void (*msp430x_dma_cbp_t)(void * args);
/**
* @brief DMA callback, function and argument.
*/
typedef struct {
- msp430x_dma_cbp_t callback; /**< @brief Callback function pointer */
- void * args; /**< @brief Callback function arguments */
+ msp430x_dma_cbp_t callback; /**< @brief Callback function pointer */
+ void * args; /**< @brief Callback function arguments */
} msp430x_dma_cb_t;
/**
* @brief MSP430X DMA request structure.
*/
typedef struct {
- void * source_addr; /**< @brief Source address */
- void * dest_addr; /**< @brief Destination address */
- uint16_t size; /**< @brief Number of values to transfer */
- uint16_t addr_mode; /**< @brief Address manipulation mode */
- uint16_t data_mode; /**< @brief Data sizes (b2b, w2w, b2w, w2b) */
- uint16_t transfer_mode; /**< @brief Transfer mode (single, block, burst) */
- uint16_t trigger; /**< @brief Triggering event (see datasheet) */
- msp430x_dma_cb_t callback;/**< @brief Callback function and arguments */
+ const void * source_addr; /**< @brief Source address */
+ void * dest_addr; /**< @brief Destination address */
+ uint16_t size; /**< @brief Number of values to transfer */
+ uint16_t addr_mode; /**< @brief Address manipulation mode */
+ uint16_t data_mode; /**< @brief Data sizes (b2b, w2w, b2w, w2b) */
+ uint16_t transfer_mode; /**< @brief Transfer mode (single, block, burst) */
+ uint16_t trigger; /**< @brief Triggering event (see datasheet) */
+ msp430x_dma_cb_t callback; /**< @brief Callback function and arguments */
} msp430x_dma_req_t;
/**
@@ -133,7 +133,7 @@ typedef struct {
*/
typedef struct {
msp430x_dma_ch_reg_t * registers; /**< @brief Pointer to channel registers */
- volatile uint8_t * ctl; /**< @brief Pointer to channel control register */
+ uint8_t index; /**< @brief Index of channel trigger control register */
msp430x_dma_cb_t * cb; /**< @brief Pointer to callback function and args */
} msp430x_dma_ch_t;
@@ -143,11 +143,11 @@ typedef struct {
/**
* @brief Identifies a DMA trigger using a mnemonic.
- *
+ *
* @param[in] mnem The mnemonic for the trigger, e.g. UCA0RXIFG to trigger
* on UART receive.
*/
-#define DMA_TRIGGER_MNEM(mnem) DMA0TSEL__ ## mnem
+#define DMA_TRIGGER_MNEM(mnem) DMA0TSEL__##mnem
/** @} */
@@ -158,12 +158,12 @@ typedef struct {
#ifdef __cplusplus
extern "C" {
#endif
- void dmaInit(void);
- bool dmaRequest(msp430x_dma_req_t * request, systime_t timeout);
- bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index);
- void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request);
- void dmaRelease(msp430x_dma_ch_t * channel);
-
+void dmaInit(void);
+bool dmaRequest(msp430x_dma_req_t * request, systime_t timeout);
+bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index);
+void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request);
+void dmaRelease(msp430x_dma_ch_t * channel);
+
#ifdef __cplusplus
}
#endif
@@ -171,4 +171,3 @@ extern "C" {
#endif /* HAL_USE_DMA == true */
#endif /* HAL_MSP430X_DMA_H */
-
diff --git a/os/hal/ports/MSP430X/hal_pal_lld.h b/os/hal/ports/MSP430X/hal_pal_lld.h
index 8789ed1..0b6363b 100644
--- a/os/hal/ports/MSP430X/hal_pal_lld.h
+++ b/os/hal/ports/MSP430X/hal_pal_lld.h
@@ -42,25 +42,25 @@
/**
* @brief Alternate mode 1
*/
-#define PAL_MSP430X_ALTERNATE_1 8
+#define PAL_MSP430X_ALTERNATE_1 8
/**
* @brief Alternate mode 2
*/
-#define PAL_MSP430X_ALTERNATE_2 9
+#define PAL_MSP430X_ALTERNATE_2 9
/**
* @brief Alternate mode 3
*/
-#define PAL_MSP430X_ALTERNATE_3 10
+#define PAL_MSP430X_ALTERNATE_3 10
-#define ALTERNATE_HELP(n) (PAL_MSP430X_ALTERNATE_ ## n)
+#define ALTERNATE_HELP(n) (PAL_MSP430X_ALTERNATE_##n)
/**
* @brief Alternate function.
- *
+ *
* @param[in] n alternate function selector - 1 through 3
*/
-#define PAL_MODE_ALTERNATE(n) (ALTERNATE_HELP(n))
+#define PAL_MODE_ALTERNATE(n) (ALTERNATE_HELP(n))
/** @} */
@@ -75,17 +75,16 @@
/**
* @brief Width, in bits, of an I/O port.
*/
-#define PAL_IOPORTS_WIDTH 16U
+#define PAL_IOPORTS_WIDTH 16U
/**
* @brief Whole port mask.
* @details This macro specifies all the valid bits into a port.
*/
-#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFU)
+#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFU)
/** @} */
-
/**
* @name Line handling macros
* @{
@@ -97,25 +96,24 @@
* @note In this driver the pad number is encoded in the upper 4 bits of
* the GPIO address which are guaranteed to be zero.
*/
-#define PAL_LINE(port, pad) \
+#define PAL_LINE(port, pad) \
((ioline_t)((uint16_t)(port)) | (((uint16_t)(pad)) << 12))
/**
* @brief Decodes a port identifier from a line identifier.
*/
-#define PAL_PORT(line) \
+#define PAL_PORT(line) \
((msp430x_gpio_registers_t *)(((uint16_t)(line)) & 0x0FFFU))
/**
* @brief Decodes a pad identifier from a line identifier.
*/
-#define PAL_PAD(line) \
- ((uint16_t)((uint16_t)(line) >> 12))
+#define PAL_PAD(line) ((uint16_t)((uint16_t)(line) >> 12))
/**
* @brief Value identifying an invalid line.
*/
-#define PAL_NOLINE 0U
+#define PAL_NOLINE 0U
/** @} */
/**
@@ -220,35 +218,35 @@ typedef msp430x_gpio_registers_t * ioportid_t;
* @brief GPIO port A identifier.
*/
#if defined(PA_BASE) || defined(__DOXYGEN__)
-#define IOPORT1 ((volatile msp430x_gpio_registers_t *)PA_BASE)
+#define IOPORT1 ((volatile msp430x_gpio_registers_t *)PA_BASE)
#endif
/**
* @brief GPIO port B identifier.
*/
#if defined(PB_BASE) || defined(__DOXYGEN__)
-#define IOPORT2 ((volatile msp430x_gpio_registers_t *)PB_BASE)
+#define IOPORT2 ((volatile msp430x_gpio_registers_t *)PB_BASE)
#endif
/**
* @brief GPIO port C identifier.
*/
#if defined(PC_BASE) || defined(__DOXYGEN__)
-#define IOPORT3 ((volatile msp430x_gpio_registers_t *)PC_BASE)
+#define IOPORT3 ((volatile msp430x_gpio_registers_t *)PC_BASE)
#endif
/**
* @brief GPIO port D identifier.
*/
#if defined(PD_BASE) || defined(__DOXYGEN__)
-#define IOPORT4 ((volatile msp430x_gpio_registers_t *)PD_BASE)
+#define IOPORT4 ((volatile msp430x_gpio_registers_t *)PD_BASE)
#endif
/**
* @brief GPIO port E identifier.
*/
#if defined(PE_BASE) || defined(__DOXYGEN__)
-#define IOPORT5 ((volatile msp430x_gpio_registers_t *)PE_BASE)
+#define IOPORT5 ((volatile msp430x_gpio_registers_t *)PE_BASE)
#endif
/**
@@ -261,7 +259,7 @@ typedef msp430x_gpio_registers_t * ioportid_t;
/**
* @brief GPIO port J identifier.
*/
-#define IOPORT0 ((volatile msp430x_gpio_registers_t *)PJ_BASE)
+#define IOPORT0 ((volatile msp430x_gpio_registers_t *)PJ_BASE)
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
@@ -307,8 +305,7 @@ typedef msp430x_gpio_registers_t * ioportid_t;
*
* @notapi
*/
-#define pal_lld_writeport(port, bits) ((port)->out = (bits))
-
+#define pal_lld_writeport(port, bits) ((port)->out = (bits))
/**
* @brief Sets a bits mask on a I/O port.
@@ -353,7 +350,7 @@ typedef msp430x_gpio_registers_t * ioportid_t;
*
* @notapi
*/
-#define pal_lld_setgroupmode(port, mask, offset, mode) \
+#define pal_lld_setgroupmode(port, mask, offset, mode) \
_pal_lld_setgroupmode(port, mask << offset, mode)
/**
@@ -366,7 +363,7 @@ typedef msp430x_gpio_registers_t * ioportid_t;
*
* @notapi
*/
-#define pal_lld_clearpad(port, pad) ((port)->out &= ~(BIT ## pad))
+#define pal_lld_clearpad(port, pad) ((port)->out &= ~(1 << pad))
#if !defined(__DOXYGEN__)
extern const PALConfig pal_default_config;
@@ -375,10 +372,8 @@ extern const PALConfig pal_default_config;
#ifdef __cplusplus
extern "C" {
#endif
- void _pal_lld_init(const PALConfig *config);
- void _pal_lld_setgroupmode(ioportid_t port,
- ioportmask_t mask,
- iomode_t mode);
+void _pal_lld_init(const PALConfig * config);
+void _pal_lld_setgroupmode(ioportid_t port, ioportmask_t mask, iomode_t mode);
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/ports/MSP430X/hal_serial_lld.c b/os/hal/ports/MSP430X/hal_serial_lld.c
index bc002cb..0d9aa1c 100644
--- a/os/hal/ports/MSP430X/hal_serial_lld.c
+++ b/os/hal/ports/MSP430X/hal_serial_lld.c
@@ -37,33 +37,49 @@
/** @brief USART0 serial driver identifier.*/
#if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__)
#ifndef __MSP430_HAS_EUSCI_A0__
- #error "Cannot find USCI module to use for SD0"
+#error "Cannot find USCI module to use for SD0"
+#endif
+#ifdef MSP430X_USCI_A0_USED
+#error "USCI module A0 already in use - USART0 not available"
#endif
SerialDriver SD0;
+#define MSP430X_USCI_A0_USED
#endif
/** @brief USART1 serial driver identifier.*/
#if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__)
#ifndef __MSP430_HAS_EUSCI_A1__
- #error "Cannot find USCI module to use for SD1"
+#error "Cannot find USCI module to use for SD1"
+#endif
+#ifdef MSP430X_USCI_A1_USED
+#error "USCI module A1 already in use - USART1 not available"
#endif
SerialDriver SD1;
+#define MSP430X_USCI_A1_USED
#endif
/** @brief USART2 serial driver identifier.*/
#if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__)
#ifndef __MSP430_HAS_EUSCI_A2__
- #error "Cannot find USCI module to use for SD2"
+#error "Cannot find USCI module to use for SD2"
+#endif
+#ifdef MSP430X_USCI_A2_USED
+#error "USCI module A2 already in use - USART2 not available"
#endif
SerialDriver SD2;
+#define MSP430X_USCI_A2_USED
#endif
/** @brief USART3 serial driver identifier.*/
#if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__)
#ifndef __MSP430_HAS_EUSCI_A3__
- #error "Cannot find USCI module to use for SD3"
+#error "Cannot find USCI module to use for SD3"
+#endif
+#ifdef MSP430X_USCI_A3_USED
+#error "USCI module A3 already in use - USART3 not available"
#endif
SerialDriver SD3;
+#define MSP430X_USCI_A3_USED
#endif
/*===========================================================================*/
@@ -73,9 +89,7 @@ SerialDriver SD3;
/**
* @brief Driver default configuration.
*/
-static const SerialConfig default_config = {
- SERIAL_DEFAULT_BITRATE
-};
+static const SerialConfig default_config = { SERIAL_DEFAULT_BITRATE };
/*===========================================================================*/
/* Driver local functions. */
@@ -85,7 +99,7 @@ static const SerialConfig default_config = {
* @brief UCBRS calculation.
* @details This function calculates the UCBRS value for oversampled baud
* rates.
- *
+ *
* @param[in] frac Fractional part of baud rate division, times 10000.
*/
static uint8_t UCBRS(uint16_t frac) {
@@ -160,7 +174,7 @@ static uint8_t UCBRS(uint16_t frac) {
return 0xFB;
else if (frac < 9288)
return 0xFD;
- else
+ else
return 0xFE;
}
@@ -168,13 +182,13 @@ static uint8_t UCBRS(uint16_t frac) {
* @brief Modulation control word calculator.
* @details This function calculates the modulation control word from the
* input clock frequency and the requested baud rate.
- *
+ *
* @param[in] baud Requested baud rate
* @param[in] freq Frequency of the clock driving the USCI module
*/
static uint16_t UCAxMCTLW(uint32_t baud, uint32_t freq) {
-
- uint16_t n = freq/baud;
+
+ uint16_t n = freq / baud;
/*uint16_t frac = (freq * 10000 / baud) - ((freq / baud) * 10000);*/
uint16_t frac = (freq - (n * baud)) * 10000 / baud;
if (n > 16) {
@@ -190,12 +204,12 @@ static uint16_t UCAxMCTLW(uint32_t baud, uint32_t freq) {
* @brief UCBRW calculation.
* @details This function calculates the UCBRW value for all baud
* rates.
- *
+ *
* @param[in] baud Requested baud rate
* @param[in] freq Frequency of the clock driving the USCI module
*/
static uint16_t UCAxBRW(uint32_t baud, uint32_t freq) {
- uint16_t n = freq/baud;
+ uint16_t n = freq / baud;
if (n > 16) {
return n >> 4;
}
@@ -203,88 +217,88 @@ static uint16_t UCAxBRW(uint32_t baud, uint32_t freq) {
}
#if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__)
-static void usart0_init(const SerialConfig *config) {
- UCA0BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ);
+static void usart0_init(const SerialConfig * config) {
+ UCA0BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ);
UCA0MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ);
UCA0STATW = 0;
UCA0ABCTL = 0;
UCA0IRCTL = 0;
- UCA0CTLW0 = (MSP430X_USART0_PARITY << 14) | (MSP430X_USART0_ORDER << 13) | \
- (MSP430X_USART0_SIZE << 12) | (MSP430X_USART0_STOP << 11) | \
+ UCA0CTLW0 = (MSP430X_USART0_PARITY << 14) | (MSP430X_USART0_ORDER << 13) |
+ (MSP430X_USART0_SIZE << 12) | (MSP430X_USART0_STOP << 11) |
(MSP430X_USART0_UCSSEL);
UCA0IE = UCRXIE;
}
#endif
#if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__)
-static void usart1_init(const SerialConfig *config) {
- UCA1BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ);
+static void usart1_init(const SerialConfig * config) {
+ UCA1BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ);
UCA1MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ);
UCA1STATW = 0;
UCA1ABCTL = 0;
UCA1IRCTL = 0;
- UCA1CTLW0 = (MSP430X_USART1_PARITY << 14) | (MSP430X_USART1_ORDER << 13) | \
- (MSP430X_USART1_SIZE << 12) | (MSP430X_USART1_STOP << 11) | \
+ UCA1CTLW0 = (MSP430X_USART1_PARITY << 14) | (MSP430X_USART1_ORDER << 13) |
+ (MSP430X_USART1_SIZE << 12) | (MSP430X_USART1_STOP << 11) |
(MSP430X_USART1_UCSSEL);
UCA1IE = UCRXIE;
}
#endif
#if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__)
-static void usart2_init(const SerialConfig *config) {
- UCA2BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART2_CLK_FREQ);
+static void usart2_init(const SerialConfig * config) {
+ UCA2BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART2_CLK_FREQ);
UCA2MCTLW = UCAxMCTLW(config->sc_bitrate);
UCA2STATW = 0;
UCA2ABCTL = 0;
UCA2IRCTL = 0;
- UCA2CTLW0 = (MSP430X_USART2_PARITY << 14) | (MSP430X_USART2_ORDER << 13) | \
- (MSP430X_USART2_SIZE << 12) | (MSP430X_USART2_STOP << 11) | \
+ UCA2CTLW0 = (MSP430X_USART2_PARITY << 14) | (MSP430X_USART2_ORDER << 13) |
+ (MSP430X_USART2_SIZE << 12) | (MSP430X_USART2_STOP << 11) |
(MSP430X_USART2_UCSSEL);
UCA2IE = UCRXIE;
}
#endif
#if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__)
-static void usart3_init(const SerialConfig *config) {
- UCA3BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ);
+static void usart3_init(const SerialConfig * config) {
+ UCA3BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ);
UCA3MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ);
UCA3STATW = 0;
UCA3ABCTL = 0;
UCA3IRCTL = 0;
- UCA3CTLW0 = (MSP430X_USART3_PARITY << 14) | (MSP430X_USART3_ORDER << 13) | \
- (MSP430X_USART3_SIZE << 12) | (MSP430X_USART3_STOP << 11) | \
+ UCA3CTLW0 = (MSP430X_USART3_PARITY << 14) | (MSP430X_USART3_ORDER << 13) |
+ (MSP430X_USART3_SIZE << 12) | (MSP430X_USART3_STOP << 11) |
(MSP430X_USART3_UCSSEL);
UCA3IE = UCRXIE;
}
#endif
#if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__)
-static void notify0(io_queue_t *qp) {
-
+static void notify0(io_queue_t * qp) {
+
(void)qp;
UCA0IE |= UCTXIE;
}
#endif
#if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__)
-static void notify1(io_queue_t *qp) {
-
+static void notify1(io_queue_t * qp) {
+
(void)qp;
UCA1IE |= UCTXIE;
}
#endif
#if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__)
-static void notify2(io_queue_t *qp) {
-
+static void notify2(io_queue_t * qp) {
+
(void)qp;
UCA2IE |= UCTXIE;
}
#endif
#if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__)
-static void notify3(io_queue_t *qp) {
-
+static void notify3(io_queue_t * qp) {
+
(void)qp;
UCA3IE |= UCTXIE;
}
@@ -292,24 +306,23 @@ static void notify3(io_queue_t *qp) {
/**
* @brief Error handling routine.
- *
+ *
* @param[in] sra USCI status register containing errors
* @param[in] sdp pointer to a @p SerialDriver object
*/
-static void set_error(uint16_t sra, SerialDriver *sdp) {
- eventflags_t sts = 0;
-
- if (sra & UCOE)
- sts |= SD_OVERRUN_ERROR;
- if (sra & UCPE)
- sts |= SD_PARITY_ERROR;
- if (sra & UCFE)
- sts |= SD_FRAMING_ERROR;
- osalSysLockFromISR();
- chnAddFlagsI(sdp, sts);
- osalSysUnlockFromISR();
+static void set_error(uint16_t sra, SerialDriver * sdp) {
+ eventflags_t sts = 0;
+
+ if (sra & UCOE)
+ sts |= SD_OVERRUN_ERROR;
+ if (sra & UCPE)
+ sts |= SD_PARITY_ERROR;
+ if (sra & UCFE)
+ sts |= SD_FRAMING_ERROR;
+ osalSysLockFromISR();
+ chnAddFlagsI(sdp, sts);
+ osalSysUnlockFromISR();
}
-
/*===========================================================================*/
/* Driver interrupt handlers. */
@@ -318,236 +331,235 @@ static void set_error(uint16_t sra, SerialDriver *sdp) {
#if MSP430X_SERIAL_USE_USART0 || defined(__DOXYGEN__)
/**
* @brief USART0 interrupt handler.
- *
+ *
* @isr
*/
PORT_IRQ_HANDLER(USCI_A0_VECTOR) {
msg_t b;
-
+
OSAL_IRQ_PROLOGUE();
-
- switch (__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG)) {
- case USCI_UART_UCRXIFG: /* RX interrupt */
-
- /* Detect errors */
- if (UCA0STATW & UCRXERR)
- set_error(UCA0STATW, &SD0);
-
- /* Data available */
- osalSysLockFromISR();
- sdIncomingDataI(&SD0, UCA0RXBUF);
- osalSysUnlockFromISR();
- break;
-
- case USCI_UART_UCTXIFG: /* TX interrupt */
-
- /* Transmission buffer empty */
- osalSysLockFromISR();
- b = sdRequestDataI(&SD0);
- if (b < Q_OK) {
- chnAddFlagsI(&SD0, CHN_OUTPUT_EMPTY);
- UCA0IE = (UCA0IE & ~UCTXIE) | UCTXCPTIE;
- UCA0IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
- }
- else
- UCA0TXBUF = b;
- osalSysUnlockFromISR();
- break;
-
- case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
-
- /* Physical transmission end */
- osalSysLockFromISR();
- if (oqIsEmptyI(&SD0.oqueue))
- chnAddFlagsI(&SD0, CHN_TRANSMISSION_END);
- UCA0IE &= ~UCTXCPTIE;
- break;
-
- default: /* other interrupts */
- while (1);
- break;
+
+ switch (__even_in_range(UCA0IV, USCI_UART_UCTXCPTIFG)) {
+ case USCI_UART_UCRXIFG: /* RX interrupt */
+
+ /* Detect errors */
+ if (UCA0STATW & UCRXERR)
+ set_error(UCA0STATW, &SD0);
+
+ /* Data available */
+ osalSysLockFromISR();
+ sdIncomingDataI(&SD0, UCA0RXBUF);
+ osalSysUnlockFromISR();
+ break;
+
+ case USCI_UART_UCTXIFG: /* TX interrupt */
+
+ /* Transmission buffer empty */
+ osalSysLockFromISR();
+ b = sdRequestDataI(&SD0);
+ if (b < Q_OK) {
+ chnAddFlagsI(&SD0, CHN_OUTPUT_EMPTY);
+ UCA0IE = (UCA0IE & ~UCTXIE) | UCTXCPTIE;
+ UCA0IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
+ }
+ else
+ UCA0TXBUF = b;
+ osalSysUnlockFromISR();
+ break;
+
+ case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
+
+ /* Physical transmission end */
+ osalSysLockFromISR();
+ if (oqIsEmptyI(&SD0.oqueue))
+ chnAddFlagsI(&SD0, CHN_TRANSMISSION_END);
+ UCA0IE &= ~UCTXCPTIE;
+ break;
+
+ default: /* other interrupts */
+ while (1)
+ ;
+ break;
}
-
+
OSAL_IRQ_EPILOGUE();
-
}
#endif
#if MSP430X_SERIAL_USE_USART1 || defined(__DOXYGEN__)
/**
* @brief USART1 interrupt handler.
- *
+ *
* @isr
*/
PORT_IRQ_HANDLER(USCI_A1_VECTOR) {
msg_t b;
-
+
OSAL_IRQ_PROLOGUE();
-
- switch (__even_in_range(UCA1IV,USCI_UART_UCTXCPTIFG)) {
- case USCI_UART_UCRXIFG: /* RX interrupt */
-
- /* Detect errors */
- if (UCA1STATW & UCRXERR)
- set_error(UCA1STATW, &SD1);
-
- /* Data available */
- osalSysLockFromISR();
- sdIncomingDataI(&SD1, UCA1RXBUF);
- osalSysUnlockFromISR();
- break;
-
- case USCI_UART_UCTXIFG: /* TX interrupt */
-
- /* Transmission buffer empty */
- osalSysLockFromISR();
- b = sdRequestDataI(&SD1);
- if (b < Q_OK) {
- chnAddFlagsI(&SD1, CHN_OUTPUT_EMPTY);
- UCA1IE = (UCA1IE & ~UCTXIE) | UCTXCPTIE;
- UCA1IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
- }
- else
- UCA1TXBUF = b;
- osalSysUnlockFromISR();
- break;
-
- case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
-
- /* Physical transmission end */
- osalSysLockFromISR();
- if (oqIsEmptyI(&SD1.oqueue))
- chnAddFlagsI(&SD1, CHN_TRANSMISSION_END);
- UCA1IE &= ~UCTXCPTIE;
- break;
-
- default: /* other interrupts */
- while (1);
- break;
+
+ switch (__even_in_range(UCA1IV, USCI_UART_UCTXCPTIFG)) {
+ case USCI_UART_UCRXIFG: /* RX interrupt */
+
+ /* Detect errors */
+ if (UCA1STATW & UCRXERR)
+ set_error(UCA1STATW, &SD1);
+
+ /* Data available */
+ osalSysLockFromISR();
+ sdIncomingDataI(&SD1, UCA1RXBUF);
+ osalSysUnlockFromISR();
+ break;
+
+ case USCI_UART_UCTXIFG: /* TX interrupt */
+
+ /* Transmission buffer empty */
+ osalSysLockFromISR();
+ b = sdRequestDataI(&SD1);
+ if (b < Q_OK) {
+ chnAddFlagsI(&SD1, CHN_OUTPUT_EMPTY);
+ UCA1IE = (UCA1IE & ~UCTXIE) | UCTXCPTIE;
+ UCA1IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
+ }
+ else
+ UCA1TXBUF = b;
+ osalSysUnlockFromISR();
+ break;
+
+ case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
+
+ /* Physical transmission end */
+ osalSysLockFromISR();
+ if (oqIsEmptyI(&SD1.oqueue))
+ chnAddFlagsI(&SD1, CHN_TRANSMISSION_END);
+ UCA1IE &= ~UCTXCPTIE;
+ break;
+
+ default: /* other interrupts */
+ while (1)
+ ;
+ break;
}
-
+
OSAL_IRQ_EPILOGUE();
-
}
#endif
#if MSP430X_SERIAL_USE_USART2 || defined(__DOXYGEN__)
/**
* @brief USART2 interrupt handler.
- *
+ *
* @isr
*/
PORT_IRQ_HANDLER(USCI_A2_VECTOR) {
msg_t b;
-
+
OSAL_IRQ_PROLOGUE();
-
- switch (__even_in_range(UCA2IV,USCI_UART_UCTXCPTIFG)) {
- case USCI_UART_UCRXIFG: /* RX interrupt */
-
- /* Detect errors */
- if (UCA2STATW & UCRXERR)
- set_error(UCA2STATW, &SD2);
-
- /* Data available */
- osalSysLockFromISR();
- sdIncomingDataI(&SD2, UCA2RXBUF);
- osalSysUnlockFromISR();
- break;
-
- case USCI_UART_UCTXIFG: /* TX interrupt */
-
- /* Transmission buffer empty */
- osalSysLockFromISR();
- b = sdRequestDataI(&SD2);
- if (b < Q_OK) {
- chnAddFlagsI(&SD2, CHN_OUTPUT_EMPTY);
- UCA2IE = (UCA2IE & ~UCTXIE) | UCTXCPTIE;
- UCA2IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
- }
- else
- UCA2TXBUF = b;
- osalSysUnlockFromISR();
- break;
-
- case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
-
- /* Physical transmission end */
- osalSysLockFromISR();
- if (oqIsEmptyI(&SD2.oqueue))
- chnAddFlagsI(&SD2, CHN_TRANSMISSION_END);
- UCA2IE &= ~UCTXCPTIE;
- break;
-
- default: /* other interrupts */
- while (1);
- break;
+
+ switch (__even_in_range(UCA2IV, USCI_UART_UCTXCPTIFG)) {
+ case USCI_UART_UCRXIFG: /* RX interrupt */
+
+ /* Detect errors */
+ if (UCA2STATW & UCRXERR)
+ set_error(UCA2STATW, &SD2);
+
+ /* Data available */
+ osalSysLockFromISR();
+ sdIncomingDataI(&SD2, UCA2RXBUF);
+ osalSysUnlockFromISR();
+ break;
+
+ case USCI_UART_UCTXIFG: /* TX interrupt */
+
+ /* Transmission buffer empty */
+ osalSysLockFromISR();
+ b = sdRequestDataI(&SD2);
+ if (b < Q_OK) {
+ chnAddFlagsI(&SD2, CHN_OUTPUT_EMPTY);
+ UCA2IE = (UCA2IE & ~UCTXIE) | UCTXCPTIE;
+ UCA2IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
+ }
+ else
+ UCA2TXBUF = b;
+ osalSysUnlockFromISR();
+ break;
+
+ case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
+
+ /* Physical transmission end */
+ osalSysLockFromISR();
+ if (oqIsEmptyI(&SD2.oqueue))
+ chnAddFlagsI(&SD2, CHN_TRANSMISSION_END);
+ UCA2IE &= ~UCTXCPTIE;
+ break;
+
+ default: /* other interrupts */
+ while (1)
+ ;
+ break;
}
-
+
OSAL_IRQ_EPILOGUE();
-
}
#endif
#if MSP430X_SERIAL_USE_USART3 || defined(__DOXYGEN__)
/**
* @brief USART3 interrupt handler.
- *
+ *
* @isr
*/
PORT_IRQ_HANDLER(USCI_A3_VECTOR) {
msg_t b;
-
+
OSAL_IRQ_PROLOGUE();
-
- switch (__even_in_range(UCA3IV,USCI_UART_UCTXCPTIFG)) {
- case USCI_UART_UCRXIFG: /* RX interrupt */
-
- /* Detect errors */
- if (UCA3STATW & UCRXERR)
- set_error(UCA3STATW, &SD3);
-
- /* Data available */
- osalSysLockFromISR();
- sdIncomingDataI(&SD3, UCA3RXBUF);
- osalSysUnlockFromISR();
- break;
-
- case USCI_UART_UCTXIFG: /* TX interrupt */
-
- /* Transmission buffer empty */
- osalSysLockFromISR();
- b = sdRequestDataI(&SD3);
- if (b < Q_OK) {
- chnAddFlagsI(&SD3, CHN_OUTPUT_EMPTY);
- UCA3IE = (UCA3IE & ~UCTXIE) | UCTXCPTIE;
- UCA3IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
- }
- else
- UCA3TXBUF = b;
- osalSysUnlockFromISR();
- break;
-
- case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
-
- /* Physical transmission end */
- osalSysLockFromISR();
- if (oqIsEmptyI(&SD3.oqueue))
- chnAddFlagsI(&SD3, CHN_TRANSMISSION_END);
- UCA3IE &= ~UCTXCPTIE;
- break;
-
- default: /* other interrupts */
- while (1);
- break;
+
+ switch (__even_in_range(UCA3IV, USCI_UART_UCTXCPTIFG)) {
+ case USCI_UART_UCRXIFG: /* RX interrupt */
+
+ /* Detect errors */
+ if (UCA3STATW & UCRXERR)
+ set_error(UCA3STATW, &SD3);
+
+ /* Data available */
+ osalSysLockFromISR();
+ sdIncomingDataI(&SD3, UCA3RXBUF);
+ osalSysUnlockFromISR();
+ break;
+
+ case USCI_UART_UCTXIFG: /* TX interrupt */
+
+ /* Transmission buffer empty */
+ osalSysLockFromISR();
+ b = sdRequestDataI(&SD3);
+ if (b < Q_OK) {
+ chnAddFlagsI(&SD3, CHN_OUTPUT_EMPTY);
+ UCA3IE = (UCA3IE & ~UCTXIE) | UCTXCPTIE;
+ UCA3IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
+ }
+ else
+ UCA3TXBUF = b;
+ osalSysUnlockFromISR();
+ break;
+
+ case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
+
+ /* Physical transmission end */
+ osalSysLockFromISR();
+ if (oqIsEmptyI(&SD3.oqueue))
+ chnAddFlagsI(&SD3, CHN_TRANSMISSION_END);
+ UCA3IE &= ~UCTXCPTIE;
+ break;
+
+ default: /* other interrupts */
+ while (1)
+ ;
+ break;
}
-
+
OSAL_IRQ_EPILOGUE();
-
}
#endif
-
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@@ -586,13 +598,12 @@ void sd_lld_init(void) {
*
* @notapi
*/
-void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
+void sd_lld_start(SerialDriver * sdp, const SerialConfig * config) {
if (config == NULL) {
config = &default_config;
}
-
if (sdp->state == SD_STOP) {
#if MSP430X_SERIAL_USE_USART0 == TRUE
if (&SD0 == sdp) {
@@ -626,7 +637,7 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
*
* @notapi
*/
-void sd_lld_stop(SerialDriver *sdp) {
+void sd_lld_stop(SerialDriver * sdp) {
if (sdp->state == SD_READY) {
#if MSP430X_SERIAL_USE_USART0 == TRUE
diff --git a/os/hal/ports/MSP430X/hal_spi_lld.c b/os/hal/ports/MSP430X/hal_spi_lld.c
new file mode 100644
index 0000000..70a357e
--- /dev/null
+++ b/os/hal/ports/MSP430X/hal_spi_lld.c
@@ -0,0 +1,578 @@
+/*
+ ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_spi_lld.c
+ * @brief MSP430X SPI subsystem low level driver source.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief SPIA0 driver identifier.
+ */
+#if (MSP430X_SPI_USE_SPIA0 == TRUE) || defined(__DOXYGEN__)
+SPIDriver SPIDA0;
+#endif
+
+/**
+ * @brief SPIA1 driver identifier.
+ */
+#if (MSP430X_SPI_USE_SPIA1 == TRUE) || defined(__DOXYGEN__)
+SPIDriver SPIDA1;
+#endif
+
+/**
+ * @brief SPIA2 driver identifier.
+ */
+#if (MSP430X_SPI_USE_SPIA2 == TRUE) || defined(__DOXYGEN__)
+SPIDriver SPIDA2;
+#endif
+
+/**
+ * @brief SPIA3 driver identifier.
+ */
+#if (MSP430X_SPI_USE_SPIA3 == TRUE) || defined(__DOXYGEN__)
+SPIDriver SPIDA3;
+#endif
+
+/**
+ * @brief SPIB0 driver identifier.
+ */
+#if (MSP430X_SPI_USE_SPIB0 == TRUE) || defined(__DOXYGEN__)
+SPIDriver SPIDB0;
+#endif
+
+/**
+ * @brief SPIB1 driver identifier.
+ */
+#if (MSP430X_SPI_USE_SPIB1 == TRUE) || defined(__DOXYGEN__)
+SPIDriver SPIDB1;
+#endif
+
+/**
+ * @brief SPIB2 driver identifier.
+ */
+#if (MSP430X_SPI_USE_SPIB2 == TRUE) || defined(__DOXYGEN__)
+SPIDriver SPIDB2;
+#endif
+
+/**
+ * @brief SPIB3 driver identifier.
+ */
+#if (MSP430X_SPI_USE_SPIB3 == TRUE) || defined(__DOXYGEN__)
+SPIDriver SPIDB3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+static const uint16_t dummytx = 0xFFFFU;
+static uint16_t dummyrx;
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static void init_transfer(SPIDriver * spip) {
+
+#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE || defined(__DOXYGEN__)
+ if (spip->config->dmarx_index > MSP430X_DMA_CHANNELS) {
+ dmaRequest(&(spip->rx_req), TIME_INFINITE);
+ }
+ else {
+ dmaTransfer(&(spip->dmarx), &(spip->rx_req));
+ }
+ if (spip->config->dmatx_index > MSP430X_DMA_CHANNELS) {
+ dmaRequest(&(spip->tx_req), TIME_INFINITE);
+ }
+ else {
+ dmaTransfer(&(spip->dmatx), &(spip->tx_req));
+ }
+#else
+ dmaRequest(&(spip->rx_req), TIME_INFINITE);
+ dmaRequest(&(spip->tx_req), TIME_INFINITE);
+#endif
+
+ *(spip->ifg) |= UCTXIFG;
+}
+
+/**
+ * @brief Shared end-of-transfer callback.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @note This function is called in ISR context by the DMA code.
+ */
+static void spi_lld_end_of_transfer(void * spip) {
+
+ /* So that future transfers will actually work */
+ *(((SPIDriver *)spip)->ifg) &= ~(UCTXIFG);
+ /* NOTE to future me - this macro sets the driver state and calls the
+ * configured callback end_cb, if applicable. That callback doesn't seem to
+ * be modifiable without reconfiguring the whole driver. */
+ _spi_isr_code((SPIDriver *)spip);
+}
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SPI driver initialization.
+ *
+ * @notapi
+ */
+void spi_lld_init(void) {
+
+#if MSP430X_SPI_USE_SPIA0 == TRUE
+ /* Driver initialization.*/
+ spiObjectInit(&SPIDA0);
+ SPIDA0.regs = (msp430x_spi_reg_t *)(&UCA0CTLW0);
+ SPIDA0.ifg = (volatile uint16_t *)&UCA0IFG;
+ SPIDA0.tx_req.trigger = DMA_TRIGGER_MNEM(UCA0TXIFG);
+ SPIDA0.rx_req.trigger = DMA_TRIGGER_MNEM(UCA0RXIFG);
+ SPIDA0.tx_req.dest_addr = &(SPIDA0.regs->txbuf);
+ SPIDA0.rx_req.source_addr = &(SPIDA0.regs->rxbuf);
+ SPIDA0.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDA0.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDA0.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDA0.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDA0.tx_req.callback.callback = NULL;
+ SPIDA0.tx_req.callback.args = NULL;
+ SPIDA0.rx_req.callback.callback = spi_lld_end_of_transfer;
+ SPIDA0.rx_req.callback.args = &SPIDA0;
+/* NOTE to my future self - this must be SINGLE because BLOCK and BURST
+ * don't wait for triggers and would overflow both buffers. Don't worry, it
+ * still works - the transfer isn't complete until SZ bytes are transferred */
+#endif
+
+#if MSP430X_SPI_USE_SPIA1 == TRUE
+ /* Driver initialization.*/
+ spiObjectInit(&SPIDA1);
+ SPIDA1.regs = (msp430x_spi_reg_t *)(&UCA1CTLW0);
+ SPIDA1.ifg = (volatile uint16_t *)&UCA1IFG;
+ SPIDA1.tx_req.trigger = DMA_TRIGGER_MNEM(UCA1TXIFG);
+ SPIDA1.rx_req.trigger = DMA_TRIGGER_MNEM(UCA1RXIFG);
+ SPIDA1.tx_req.dest_addr = &(SPIDA1.regs->txbuf);
+ SPIDA1.rx_req.source_addr = &(SPIDA1.regs->rxbuf);
+ SPIDA1.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDA1.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDA1.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDA1.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDA1.tx_req.callback.callback = NULL;
+ SPIDA1.tx_req.callback.args = NULL;
+ SPIDA1.rx_req.callback.callback = spi_lld_end_of_transfer;
+ SPIDA1.rx_req.callback.args = &SPIDA1;
+#endif
+
+#if MSP430X_SPI_USE_SPIA2 == TRUE
+ /* Driver initialization.*/
+ spiObjectInit(&SPIDA2);
+ SPIDA2.regs = (msp430x_spi_reg_t *)(&UCA2CTLW0);
+ SPIDA2.ifg = (volatile uint16_t *)&UCA2IFG;
+ SPIDA2.tx_req.trigger = DMA_TRIGGER_MNEM(UCA2TXIFG);
+ SPIDA2.rx_req.trigger = DMA_TRIGGER_MNEM(UCA2RXIFG);
+ SPIDA2.tx_req.dest_addr = &(SPIDA2.regs->txbuf);
+ SPIDA2.rx_req.source_addr = &(SPIDA2.regs->rxbuf);
+ SPIDA2.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDA2.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDA2.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDA2.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDA2.tx_req.callback.callback = NULL;
+ SPIDA2.tx_req.callback.args = NULL;
+ SPIDA2.rx_req.callback.callback = spi_lld_end_of_transfer;
+ SPIDA2.rx_req.callback.args = &SPIDA2;
+#endif
+
+#if MSP430X_SPI_USE_SPIA3 == TRUE
+ /* Driver initialization.*/
+ spiObjectInit(&SPIDA3);
+ SPIDA3.regs = (msp430x_spi_reg_t *)(&UCA3CTLW0);
+ SPIDA3.ifg = (volatile uint16_t *)&UCA3IFG;
+ SPIDA3.tx_req.trigger = DMA_TRIGGER_MNEM(UCA3TXIFG);
+ SPIDA3.rx_req.trigger = DMA_TRIGGER_MNEM(UCA3RXIFG);
+ SPIDA3.tx_req.dest_addr = &(SPIDA3.regs->txbuf);
+ SPIDA3.rx_req.source_addr = &(SPIDA3.regs->rxbuf);
+ SPIDA3.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDA3.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDA3.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDA3.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDA3.tx_req.callback.callback = NULL;
+ SPIDA3.tx_req.callback.args = NULL;
+ SPIDA3.rx_req.callback.callback = spi_lld_end_of_transfer;
+ SPIDA3.rx_req.callback.args = &SPIDA3;
+#endif
+
+#if MSP430X_SPI_USE_SPIB0 == TRUE
+ /* Driver initialization.*/
+ spiObjectInit(&SPIDB0);
+ SPIDB0.regs = (msp430x_spi_reg_t *)(&UCB0CTLW0);
+ SPIDB0.ifg = (volatile uint16_t *)&UCB0IFG;
+ SPIDB0.tx_req.trigger = DMA_TRIGGER_MNEM(UCB0TXIFG0);
+ SPIDB0.rx_req.trigger = DMA_TRIGGER_MNEM(UCB0RXIFG0);
+ SPIDB0.tx_req.dest_addr = &(SPIDB0.regs->txbuf);
+ SPIDB0.rx_req.source_addr = &(SPIDB0.regs->rxbuf);
+ SPIDB0.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDB0.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDB0.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDB0.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDB0.tx_req.callback.callback = NULL;
+ SPIDB0.tx_req.callback.args = NULL;
+ SPIDB0.rx_req.callback.callback = spi_lld_end_of_transfer;
+ SPIDB0.rx_req.callback.args = &SPIDB0;
+#endif
+
+#if MSP430X_SPI_USE_SPIB1 == TRUE
+ /* Driver initialization.*/
+ spiObjectInit(&SPIDB1);
+ SPIDB1.regs = (msp430x_spi_reg_t *)(&UCB1CTLW0);
+ SPIDB1.ifg = (volatile uint16_t *)&UCB1IFG;
+ SPIDB1.tx_req.trigger = DMA_TRIGGER_MNEM(UCB1TXIFG0);
+ SPIDB1.rx_req.trigger = DMA_TRIGGER_MNEM(UCB1RXIFG0);
+ SPIDB1.tx_req.dest_addr = &(SPIDB1.regs->txbuf);
+ SPIDB1.rx_req.source_addr = &(SPIDB1.regs->rxbuf);
+ SPIDB1.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDB1.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDB1.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDB1.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDB1.tx_req.callback.callback = NULL;
+ SPIDB1.tx_req.callback.args = NULL;
+ SPIDB1.rx_req.callback.callback = spi_lld_end_of_transfer;
+ SPIDB1.rx_req.callback.args = &SPIDB1;
+#endif
+
+#if MSP430X_SPI_USE_SPIB2 == TRUE
+ /* Driver initialization.*/
+ spiObjectInit(&SPIDB2);
+ SPIDB2.regs = (msp430x_spi_reg_t *)(&UCB2CTLW0);
+ SPIDB2.ifg = (volatile uint16_t *)&UCB2IFG;
+ SPIDB2.tx_req.trigger = DMA_TRIGGER_MNEM(UCB2TXIFG0);
+ SPIDB2.rx_req.trigger = DMA_TRIGGER_MNEM(UCB2RXIFG0);
+ SPIDB2.tx_req.dest_addr = &(SPIDB2.regs->txbuf);
+ SPIDB2.rx_req.source_addr = &(SPIDB2.regs->rxbuf);
+ SPIDB2.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDB2.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDB2.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDB2.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDB2.tx_req.callback.callback = NULL;
+ SPIDB2.tx_req.callback.args = NULL;
+ SPIDB2.rx_req.callback.callback = spi_lld_end_of_transfer;
+ SPIDB2.rx_req.callback.args = &SPIDB2;
+#endif
+
+#if MSP430X_SPI_USE_SPIB3 == TRUE
+ /* Driver initialization.*/
+ spiObjectInit(&SPIDB3);
+ SPIDB3.regs = (msp430x_spi_reg_t *)(&UCB3CTLW0);
+ SPIDB3.ifg = (volatile uint16_t *)&UCB3IFG;
+ SPIDB3.tx_req.trigger = DMA_TRIGGER_MNEM(UCB3TXIFG0);
+ SPIDB3.rx_req.trigger = DMA_TRIGGER_MNEM(UCB3RXIFG0);
+ SPIDB3.tx_req.dest_addr = &(SPIDB3.regs->txbuf);
+ SPIDB3.rx_req.source_addr = &(SPIDB3.regs->rxbuf);
+ SPIDB3.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDB3.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
+ SPIDB3.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDB3.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
+ SPIDB3.tx_req.callback.callback = NULL;
+ SPIDB3.tx_req.callback.args = NULL;
+ SPIDB3.rx_req.callback.callback = spi_lld_end_of_transfer;
+ SPIDB3.rx_req.callback.args = &SPIDB3;
+#endif
+}
+
+/**
+ * @brief Configures and activates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_start(SPIDriver * spip) {
+
+ if (spip->state == SPI_STOP) {
+/* Enables the peripheral.*/
+#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE
+ /* Claim DMA streams here */
+ bool b;
+ if (spip->config->dmatx_index < MSP430X_DMA_CHANNELS) {
+ b = dmaAcquire(&(spip->dmatx), spip->config->dmatx_index);
+ osalDbgAssert(!b, "stream already allocated");
+ }
+ if (spip->config->dmarx_index < MSP430X_DMA_CHANNELS) {
+ b = dmaAcquire(&(spip->dmarx), spip->config->dmarx_index);
+ osalDbgAssert(!b, "stream already allocated");
+ }
+#endif /* MSP430X_SPI_EXCLUSIVE_DMA */
+ }
+ uint16_t brw = 0;
+ uint8_t ssel = 0;
+#if MSP430X_SPI_USE_SPIA0
+ if (spip == &SPIDA0) {
+ brw = MSP430X_SPIA0_CLK_FREQ / spip->config->bit_rate;
+ ssel = MSP430X_SPIA0_UCSSEL;
+ }
+#endif
+#if MSP430X_SPI_USE_SPIA1
+ if (spip == &SPIDA1) {
+ brw = MSP430X_SPIA1_CLK_FREQ / spip->config->bit_rate;
+ ssel = MSP430X_SPIA1_UCSSEL;
+ }
+#endif
+#if MSP430X_SPI_USE_SPIA2
+ if (spip == &SPIDA2) {
+ brw = MSP430X_SPIA2_CLK_FREQ / spip->config->bit_rate;
+ ssel = MSP430X_SPIA2_UCSSEL;
+ }
+#endif
+#if MSP430X_SPI_USE_SPIA3
+ if (spip == &SPIDA3) {
+ brw = MSP430X_SPIA3_CLK_FREQ / spip->config->bit_rate;
+ ssel = MSP430X_SPIA3_UCSSEL;
+ }
+#endif
+#if MSP430X_SPI_USE_SPIB0
+ if (spip == &SPIDB0) {
+ brw = MSP430X_SPIB0_CLK_FREQ / spip->config->bit_rate;
+ ssel = MSP430X_SPIB0_UCSSEL;
+ }
+#endif
+#if MSP430X_SPI_USE_SPIB1
+ if (spip == &SPIDB1) {
+ brw = MSP430X_SPIB1_CLK_FREQ / spip->config->bit_rate;
+ ssel = MSP430X_SPIB1_UCSSEL;
+ }
+#endif
+#if MSP430X_SPI_USE_SPIB2
+ if (spip == &SPIDB2) {
+ brw = MSP430X_SPIB2_CLK_FREQ / spip->config->bit_rate;
+ ssel = MSP430X_SPIB2_UCSSEL;
+ }
+#endif
+#if MSP430X_SPI_USE_SPIB3
+ if (spip == &SPIDB3) {
+ brw = MSP430X_SPIB3_CLK_FREQ / spip->config->bit_rate;
+ ssel = MSP430X_SPIB3_UCSSEL;
+ }
+#endif
+ /* Configures the peripheral.*/
+ spip->regs->ctlw0 = UCSWRST;
+ spip->regs->brw = brw;
+ spip->regs->ctlw0 =
+ (spip->config->spi_mode << 14) | (spip->config->bit_order << 13) |
+ (spip->config->data_size << 12) | (UCMST) |
+ ((spip->config->ss_line ? 0 : 2) << 9) | (UCSYNC) | (ssel) | (UCSTEM);
+ *(spip->ifg) = 0;
+}
+
+/**
+ * @brief Deactivates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_stop(SPIDriver * spip) {
+
+ if (spip->state == SPI_READY) {
+/* Disables the peripheral.*/
+#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE
+ dmaRelease(&(spip->dmatx));
+ dmaRelease(&(spip->dmarx));
+#endif
+ spip->regs->ctlw0 = UCSWRST;
+ }
+}
+
+/**
+ * @brief Asserts the slave select signal and prepares for transfers.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_select(SPIDriver * spip) {
+
+ if (spip->config->ss_line) {
+ palClearLine(spip->config->ss_line);
+ }
+}
+
+/**
+ * @brief Deasserts the slave select signal.
+ * @details The previously selected peripheral is unselected.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_unselect(SPIDriver * spip) {
+
+ if (spip->config->ss_line) {
+ palSetLine(spip->config->ss_line);
+ }
+}
+
+/**
+ * @brief Ignores data on the SPI bus.
+ * @details This asynchronous function starts the transmission of a series of
+ * idle bytes on the SPI bus and ignores the received data.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of bytes to be ignored
+ *
+ * @notapi
+ */
+void spi_lld_ignore(SPIDriver * spip, size_t n) {
+
+ spip->tx_req.source_addr = &dummytx;
+ spip->tx_req.size = n;
+ spip->tx_req.addr_mode = 0;
+
+ spip->rx_req.dest_addr = &dummyrx;
+ spip->rx_req.size = n;
+ spip->rx_req.addr_mode = 0;
+
+ init_transfer(spip);
+}
+
+/**
+ * @brief Exchanges data on the SPI bus.
+ * @details This asynchronous function starts a simultaneous transmit/receive
+ * operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_exchange(SPIDriver * spip,
+ size_t n,
+ const void * txbuf,
+ void * rxbuf) {
+
+ spip->tx_req.source_addr = txbuf;
+ spip->tx_req.size = n;
+ spip->tx_req.addr_mode = MSP430X_DMA_SRCINCR;
+
+ spip->rx_req.dest_addr = rxbuf;
+ spip->rx_req.size = n;
+ spip->rx_req.addr_mode = MSP430X_DMA_DSTINCR;
+
+ init_transfer(spip);
+}
+
+/**
+ * @brief Sends data over the SPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void spi_lld_send(SPIDriver * spip, size_t n, const void * txbuf) {
+
+ spip->tx_req.source_addr = txbuf;
+ spip->tx_req.size = n;
+ spip->tx_req.addr_mode = MSP430X_DMA_SRCINCR;
+
+ spip->rx_req.dest_addr = &dummyrx;
+ spip->rx_req.size = n;
+ spip->rx_req.addr_mode = 0;
+
+ init_transfer(spip);
+}
+
+/**
+ * @brief Receives data from the SPI bus.
+ * @details This asynchronous function starts a receive operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_receive(SPIDriver * spip, size_t n, void * rxbuf) {
+
+ spip->tx_req.source_addr = &dummytx;
+ spip->tx_req.size = n;
+ spip->tx_req.addr_mode = 0;
+
+ spip->rx_req.dest_addr = rxbuf;
+ spip->rx_req.size = n;
+ spip->rx_req.addr_mode = MSP430X_DMA_DSTINCR;
+
+ init_transfer(spip);
+}
+
+/**
+ * @brief Exchanges one frame using a polled wait.
+ * @details This synchronous function exchanges one frame using a polled
+ * synchronization method. This function is useful when exchanging
+ * small amount of data on high speed channels, usually in this
+ * situation is much more efficient just wait for completion using
+ * polling than suspending the thread waiting for an interrupt.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] frame the data frame to send over the SPI bus
+ * @return The received data frame from the SPI bus.
+ */
+uint16_t spi_lld_polled_exchange(SPIDriver * spip, uint16_t frame) {
+
+ osalDbgAssert(!(frame & 0xFF00U), "16-bit transfers not supported");
+
+ while (!(*(spip->ifg) & UCTXIFG))
+ ;
+ spip->regs->txbuf = frame;
+ while (!(*(spip->ifg) & UCRXIFG))
+ ;
+ return spip->regs->rxbuf;
+}
+
+#endif /* HAL_USE_SPI == TRUE */
+
+/** @} */
diff --git a/os/hal/ports/MSP430X/hal_spi_lld.h b/os/hal/ports/MSP430X/hal_spi_lld.h
new file mode 100644
index 0000000..ebf14c8
--- /dev/null
+++ b/os/hal/ports/MSP430X/hal_spi_lld.h
@@ -0,0 +1,642 @@
+/*
+ ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_spi_lld.h
+ * @brief MSP430X SPI subsystem low level driver header.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#ifndef HAL_SPI_LLD_H
+#define HAL_SPI_LLD_H
+
+#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
+
+#include "hal_dma_lld.h"
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name MSP430X configuration options
+ * @{
+ */
+/**
+ * @brief SPIA0 driver enable switch.
+ * @details If set to @p TRUE the support for SPIA0 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_USE_SPIA0) || defined(__DOXYGEN__)
+#define MSP430X_SPI_USE_SPIA0 FALSE
+#endif
+
+/**
+ * @brief SPIA1 driver enable switch.
+ * @details If set to @p TRUE the support for SPIA1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_USE_SPIA1) || defined(__DOXYGEN__)
+#define MSP430X_SPI_USE_SPIA1 FALSE
+#endif
+
+/**
+ * @brief SPIA2 driver enable switch.
+ * @details If set to @p TRUE the support for SPIA2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_USE_SPIA2) || defined(__DOXYGEN__)
+#define MSP430X_SPI_USE_SPIA2 FALSE
+#endif
+
+/**
+ * @brief SPIA3 driver enable switch.
+ * @details If set to @p TRUE the support for SPIA3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_USE_SPIA3) || defined(__DOXYGEN__)
+#define MSP430X_SPI_USE_SPIA3 FALSE
+#endif
+
+/**
+ * @brief SPIB0 driver enable switch.
+ * @details If set to @p TRUE the support for SPIB0 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_USE_SPIB0) || defined(__DOXYGEN__)
+#define MSP430X_SPI_USE_SPIB0 FALSE
+#endif
+
+/**
+ * @brief SPIB1 driver enable switch.
+ * @details If set to @p TRUE the support for SPIB1 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_USE_SPIB1) || defined(__DOXYGEN__)
+#define MSP430X_SPI_USE_SPIB1 FALSE
+#endif
+
+/**
+ * @brief SPIB2 driver enable switch.
+ * @details If set to @p TRUE the support for SPIB2 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_USE_SPIB2) || defined(__DOXYGEN__)
+#define MSP430X_SPI_USE_SPIB2 FALSE
+#endif
+
+/**
+ * @brief SPIB3 driver enable switch.
+ * @details If set to @p TRUE the support for SPIB3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_USE_SPIB3) || defined(__DOXYGEN__)
+#define MSP430X_SPI_USE_SPIB3 FALSE
+#endif
+
+/**
+ * @brief Exclusive DMA enable switch.
+ * @details If set to @p TRUE the support for exclusive DMA is included.
+ * @note This increases the size of the compiled executable somewhat.
+ * @note The default is @p FALSE.
+ */
+#if !defined(MSP430X_SPI_EXCLUSIVE_DMA) | defined(__DOXYGEN__)
+#define MSP430X_SPI_EXCLUSIVE_DMA FALSE
+#endif
+
+/**
+ * @brief SPIA0 clock source switch.
+ * @details Sets the clock source for SPIA0.
+ * @note Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
+ * @note The default is @p MSP430X_SMCLK_SRC.
+ */
+#if !defined(MSP430X_SPIA0_CLK_SRC)
+ #define MSP430X_SPIA0_CLK_SRC MSP430X_SMCLK_SRC
+#endif
+
+/**
+ * @brief SPIA1 clock source switch.
+ * @details Sets the clock source for SPIA1.
+ * @note Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
+ * @note The default is @p MSP430X_SMCLK_SRC.
+ */
+#if !defined(MSP430X_SPIA1_CLK_SRC)
+ #define MSP430X_SPIA1_CLK_SRC MSP430X_SMCLK_SRC
+#endif
+
+/**
+ * @brief SPIA2 clock source switch.
+ * @details Sets the clock source for SPIA2.
+ * @note Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
+ * @note The default is @p MSP430X_SMCLK_SRC.
+ */
+#if !defined(MSP430X_SPIA2_CLK_SRC)
+ #define MSP430X_SPIA2_CLK_SRC MSP430X_SMCLK_SRC
+#endif
+
+/**
+ * @brief SPIA3 clock source switch.
+ * @details Sets the clock source for SPIA3.
+ * @note Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
+ * @note The default is @p MSP430X_SMCLK_SRC.
+ */
+#if !defined(MSP430X_SPIA3_CLK_SRC)
+ #define MSP430X_SPIA3_CLK_SRC MSP430X_SMCLK_SRC
+#endif
+
+/**
+ * @brief SPIB0 clock source switch.
+ * @details Sets the clock source for SPIB0.
+ * @note Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
+ * @note The default is @p MSP430X_SMCLK_SRC.
+ */
+#if !defined(MSP430X_SPIB0_CLK_SRC)
+ #define MSP430X_SPIB0_CLK_SRC MSP430X_SMCLK_SRC
+#endif
+
+/**
+ * @brief SPIB1 clock source switch.
+ * @details Sets the clock source for SPIB1.
+ * @note Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
+ * @note The default is @p MSP430X_SMCLK_SRC.
+ */
+#if !defined(MSP430X_SPIB1_CLK_SRC)
+ #define MSP430X_SPIB1_CLK_SRC MSP430X_SMCLK_SRC
+#endif
+
+/**
+ * @brief SPIB2 clock source switch.
+ * @details Sets the clock source for SPIB2.
+ * @note Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
+ * @note The default is @p MSP430X_SMCLK_SRC.
+ */
+#if !defined(MSP430X_SPIB2_CLK_SRC)
+ #define MSP430X_SPIB2_CLK_SRC MSP430X_SMCLK_SRC
+#endif
+
+/**
+ * @brief SPIB3 clock source switch.
+ * @details Sets the clock source for SPIB3.
+ * @note Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
+ * @note The default is @p MSP430X_SMCLK_SRC.
+ */
+#if !defined(MSP430X_SPIB3_CLK_SRC)
+ #define MSP430X_SPIB3_CLK_SRC MSP430X_SMCLK_SRC
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if MSP430X_SPI_USE_SPIA0 && !defined(__MSP430_HAS_EUSCI_A0__)
+ #error "Cannot find MSP430X_USCI module to use for SPIA0"
+#endif
+
+#if MSP430X_SPI_USE_SPIA1 && !defined(__MSP430_HAS_EUSCI_A1__)
+ #error "Cannot find MSP430X_USCI module to use for SPIA1"
+#endif
+
+#if MSP430X_SPI_USE_SPIA2 && !defined(__MSP430_HAS_EUSCI_A2__)
+ #error "Cannot find MSP430X_USCI module to use for SPIA2"
+#endif
+
+#if MSP430X_SPI_USE_SPIA3 && !defined(__MSP430_HAS_EUSCI_A3__)
+ #error "Cannot find MSP430X_USCI module to use for SPIA3"
+#endif
+
+#if MSP430X_SPI_USE_SPIB0 && !defined(__MSP430_HAS_EUSCI_B0__)
+ #error "Cannot find MSP430X_USCI module to use for SPIB0"
+#endif
+
+#if MSP430X_SPI_USE_SPIB1 && !defined(__MSP430_HAS_EUSCI_B1__)
+ #error "Cannot find MSP430X_USCI module to use for SPIB1"
+#endif
+
+#if MSP430X_SPI_USE_SPIB2 && !defined(__MSP430_HAS_EUSCI_B2__)
+ #error "Cannot find MSP430X_USCI module to use for SPIB2"
+#endif
+
+#if MSP430X_SPI_USE_SPIB3 && !defined(__MSP430_HAS_EUSCI_B3__)
+ #error "Cannot find MSP430X_USCI module to use for SPIB3"
+#endif
+
+#if MSP430X_SPI_USE_SPIA0
+ #ifdef MSP430X_USCI_A0_USED
+ #error "USCI module A0 already in use - SPIA0 not available"
+ #else
+ #define MSP430X_USCI_A0_USED
+ #endif
+#endif
+
+#if MSP430X_SPI_USE_SPIA1
+ #ifdef MSP430X_USCI_A1_USED
+ #error "USCI module A1 already in use - SPIA1 not available"
+ #else
+ #define MSP430X_USCI_A1_USED
+ #endif
+#endif
+
+#if MSP430X_SPI_USE_SPIA2
+ #ifdef MSP430X_USCI_A2_USED
+ #error "USCI module A2 already in use - SPIA2 not available"
+ #else
+ #define MSP430X_USCI_A2_USED
+ #endif
+#endif
+
+#if MSP430X_SPI_USE_SPIA3
+ #ifdef MSP430X_USCI_A3_USED
+ #error "USCI module A3 already in use - SPIA3 not available"
+ #else
+ #define MSP430X_USCI_A3_USED
+ #endif
+#endif
+
+#if MSP430X_SPI_USE_SPIB0
+ #ifdef MSP430X_USCI_B0_USED
+ #error "USCI module B0 already in use - SPIB0 not available"
+ #else
+ #define MSP430X_USCI_B0_USED
+ #endif
+#endif
+
+#if MSP430X_SPI_USE_SPIB1
+ #ifdef MSP430X_USCI_B1_USED
+ #error "USCI module B1 already in use - SPIB1 not available"
+ #else
+ #define MSP430X_USCI_B1_USED
+ #endif
+#endif
+
+#if MSP430X_SPI_USE_SPIB2
+ #ifdef MSP430X_USCI_B2_USED
+ #error "USCI module B2 already in use - SPIB2 not available"
+ #else
+ #define MSP430X_USCI_B2_USED
+ #endif
+#endif
+
+#if MSP430X_SPI_USE_SPIB3
+ #ifdef MSP430X_USCI_B3_USED
+ #error "USCI module B3 already in use - SPIB3 not available"
+ #else
+ #define MSP430X_USCI_B3_USED
+ #endif
+#endif
+
+#if defined(MSP430X_SPIA0_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIA0 TX, but requested index is invalid"
+#endif
+#if defined(MSP430X_SPIA0_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIA0 RX, but requested index is invalid"
+#endif
+
+#if defined(MSP430X_SPIA1_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIA1 TX, but requested index is invalid"
+#endif
+#if defined(MSP430X_SPIA1_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIA1 RX, but requested index is invalid"
+#endif
+
+#if defined(MSP430X_SPIA2_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIA2 TX, but requested index is invalid"
+#endif
+#if defined(MSP430X_SPIA2_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIA2 RX, but requested index is invalid"
+#endif
+
+#if defined(MSP430X_SPIA3_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIA3 TX, but requested index is invalid"
+#endif
+#if defined(MSP430X_SPIA3_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIA3 RX, but requested index is invalid"
+#endif
+
+#if defined(MSP430X_SPIB0_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIB0 TX, but requested index is invalid"
+#endif
+#if defined(MSP430X_SPIB0_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIB0 RX, but requested index is invalid"
+#endif
+
+#if defined(MSP430X_SPIB1_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIB1 TX, but requested index is invalid"
+#endif
+#if defined(MSP430X_SPIB1_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIB1 RX, but requested index is invalid"
+#endif
+
+#if defined(MSP430X_SPIB2_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIB2 TX, but requested index is invalid"
+#endif
+#if defined(MSP430X_SPIB2_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIB2 RX, but requested index is invalid"
+#endif
+
+#if defined(MSP430X_SPIB3_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIB3 TX, but requested index is invalid"
+#endif
+#if defined(MSP430X_SPIB3_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
+ #error "Requested DMA for SPIB3 RX, but requested index is invalid"
+#endif
+
+/* TODO figure out a way to check for conflicting DMA channels */
+
+#if MSP430X_SPIA0_CLK_SRC == MSP430X_ACLK_SRC
+ #define MSP430X_SPIA0_CLK_FREQ MSP430X_ACLK_FREQ
+ #define MSP430X_SPIA0_UCSSEL UCSSEL__ACLK
+#elif MSP430X_SPIA0_CLK_SRC == MSP430X_SMCLK_SRC
+ #define MSP430X_SPIA0_CLK_FREQ MSP430X_SMCLK_FREQ
+ #define MSP430X_SPIA0_UCSSEL UCSSEL__SMCLK
+#endif
+
+#if MSP430X_SPIA1_CLK_SRC == MSP430X_ACLK_SRC
+ #define MSP430X_SPIA1_CLK_FREQ MSP430X_ACLK_FREQ
+ #define MSP430X_SPIA1_UCSSEL UCSSEL__ACLK
+#elif MSP430X_SPIA1_CLK_SRC == MSP430X_SMCLK_SRC
+ #define MSP430X_SPIA1_CLK_FREQ MSP430X_SMCLK_FREQ
+ #define MSP430X_SPIA1_UCSSEL UCSSEL__SMCLK
+#endif
+
+#if MSP430X_SPIA2_CLK_SRC == MSP430X_ACLK_SRC
+ #define MSP430X_SPIA2_CLK_FREQ MSP430X_ACLK_FREQ
+ #define MSP430X_SPIA2_UCSSEL UCSSEL__ACLK
+#elif MSP430X_SPIA2_CLK_SRC == MSP430X_SMCLK_SRC
+ #define MSP430X_SPIA2_CLK_FREQ MSP430X_SMCLK_FREQ
+ #define MSP430X_SPIA2_UCSSEL UCSSEL__SMCLK
+#endif
+
+#if MSP430X_SPIA3_CLK_SRC == MSP430X_ACLK_SRC
+ #define MSP430X_SPIA3_CLK_FREQ MSP430X_ACLK_FREQ
+ #define MSP430X_SPIA3_UCSSEL UCSSEL__ACLK
+#elif MSP430X_SPIA3_CLK_SRC == MSP430X_SMCLK_SRC
+ #define MSP430X_SPIA3_CLK_FREQ MSP430X_SMCLK_FREQ
+ #define MSP430X_SPIA3_UCSSEL UCSSEL__SMCLK
+#endif
+
+#if MSP430X_SPIB0_CLK_SRC == MSP430X_ACLK_SRC
+ #define MSP430X_SPIB0_CLK_FREQ MSP430X_ACLK_FREQ
+ #define MSP430X_SPIB0_UCSSEL UCSSEL__ACLK
+#elif MSP430X_SPIB0_CLK_SRC == MSP430X_SMCLK_SRC
+ #define MSP430X_SPIB0_CLK_FREQ MSP430X_SMCLK_FREQ
+ #define MSP430X_SPIB0_UCSSEL UCSSEL__SMCLK
+#endif
+
+#if MSP430X_SPIB1_CLK_SRC == MSP430X_ACLK_SRC
+ #define MSP430X_SPIB1_CLK_FREQ MSP430X_ACLK_FREQ
+ #define MSP430X_SPIB1_UCSSEL UCSSEL__ACLK
+#elif MSP430X_SPIB1_CLK_SRC == MSP430X_SMCLK_SRC
+ #define MSP430X_SPIB1_CLK_FREQ MSP430X_SMCLK_FREQ
+ #define MSP430X_SPIB1_UCSSEL UCSSEL__SMCLK
+#endif
+
+#if MSP430X_SPIB2_CLK_SRC == MSP430X_ACLK_SRC
+ #define MSP430X_SPIB2_CLK_FREQ MSP430X_ACLK_FREQ
+ #define MSP430X_SPIB2_UCSSEL UCSSEL__ACLK
+#elif MSP430X_SPIB2_CLK_SRC == MSP430X_SMCLK_SRC
+ #define MSP430X_SPIB2_CLK_FREQ MSP430X_SMCLK_FREQ
+ #define MSP430X_SPIB2_UCSSEL UCSSEL__SMCLK
+#endif
+
+#if MSP430X_SPIB3_CLK_SRC == MSP430X_ACLK_SRC
+ #define MSP430X_SPIB3_CLK_FREQ MSP430X_ACLK_FREQ
+ #define MSP430X_SPIB3_UCSSEL UCSSEL__ACLK
+#elif MSP430X_SPIB3_CLK_SRC == MSP430X_SMCLK_SRC
+ #define MSP430X_SPIB3_CLK_FREQ MSP430X_SMCLK_FREQ
+ #define MSP430X_SPIB3_UCSSEL UCSSEL__SMCLK
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an SPI driver.
+ */
+typedef struct SPIDriver SPIDriver;
+
+/**
+ * @brief SPI notification callback type.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object triggering the
+ * callback
+ */
+typedef void (*spicallback_t)(SPIDriver *spip);
+
+/**
+ * @brief Enumerated type for SPI bit order.
+ */
+typedef enum {
+ MSP430X_SPI_BO_LSB = 0,
+ MSP430X_SPI_BO_MSB = 1
+} msp430x_spi_bit_order_t;
+
+/**
+ * @brief Enumerated type for SPI data size.
+ */
+typedef enum {
+ MSP430X_SPI_DS_EIGHT = 0,
+ MSP430X_SPI_DS_SEVEN = 1
+} msp430x_spi_data_size_t;
+
+/**
+ * @brief Driver configuration structure.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+typedef struct {
+ /**
+ * @brief Operation complete callback or @p NULL.
+ */
+ spicallback_t end_cb;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief The chip select line.
+ * @note This may be PAL_NOLINE to indicate that hardware chip select is used.
+ */
+ ioline_t ss_line;
+ /**
+ * @brief The bit rate of the SPI interface.
+ * @note Nearest available rate is used.
+ */
+ uint32_t bit_rate;
+ /**
+ * @brief The bit order of the peripheral - LSB or MSB first.
+ */
+ msp430x_spi_bit_order_t bit_order;
+ /**
+ * @brief The data size of the peripheral - 7 or 8 bits.
+ */
+ msp430x_spi_data_size_t data_size;
+ /**
+ * @brief The SPI mode to use - 0 through 3.
+ */
+ uint8_t spi_mode;
+#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE || defined(__DOXYGEN__)
+ /**
+ * @brief The index of the TX DMA channel.
+ * @note This may be >MSP430X_DMA_CHANNELS to indicate that exclusive DMA is not used.
+ */
+ uint8_t dmatx_index;
+ /**
+ * @brief The index of the RX DMA channel.
+ * @note This may be >MSP430X_DMA_CHANNELS to indicate that exclusive DMA is not used.
+ */
+ uint8_t dmarx_index;
+#endif
+} SPIConfig;
+
+/**
+ * @brief MSP430X SPI register structure.
+ */
+typedef struct {
+ uint16_t ctlw0;
+ uint16_t _padding0;
+ uint16_t _padding1;
+ uint16_t brw;
+ uint16_t statw_b;
+ uint16_t statw_a;
+ uint16_t rxbuf;
+ uint16_t txbuf;
+} msp430x_spi_reg_t;
+
+/**
+ * @brief Structure representing an SPI driver.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+struct SPIDriver {
+ /**
+ * @brief Driver state.
+ */
+ spistate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const SPIConfig *config;
+#if (SPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Waiting thread.
+ */
+ thread_reference_t thread;
+#endif /* SPI_USE_WAIT */
+#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif
+#if defined(SPI_DRIVER_EXT_FIELDS)
+ SPI_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Configuration registers.
+ */
+ msp430x_spi_reg_t * regs;
+ /**
+ * @brief Interrupt flag register.
+ */
+ volatile uint16_t * ifg;
+ /**
+ * @brief TX DMA request.
+ */
+ msp430x_dma_req_t tx_req;
+ /**
+ * @brief RX DMA request.
+ */
+ msp430x_dma_req_t rx_req;
+#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE || defined(__DOXYGEN__)
+ /**
+ * @brief TX DMA stream.
+ */
+ msp430x_dma_ch_t dmatx;
+ /**
+ * @brief RX DMA stream.
+ */
+ msp430x_dma_ch_t dmarx;
+#endif
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if (MSP430X_SPI_USE_SPIA0 == TRUE) && !defined(__DOXYGEN__)
+extern SPIDriver SPIDA0;
+#endif
+
+#if (MSP430X_SPI_USE_SPIA1 == TRUE) && !defined(__DOXYGEN__)
+extern SPIDriver SPIDA1;
+#endif
+
+#if (MSP430X_SPI_USE_SPIA2 == TRUE) && !defined(__DOXYGEN__)
+extern SPIDriver SPIDA2;
+#endif
+
+#if (MSP430X_SPI_USE_SPIA3 == TRUE) && !defined(__DOXYGEN__)
+extern SPIDriver SPIDA3;
+#endif
+
+#if (MSP430X_SPI_USE_SPIB0 == TRUE) && !defined(__DOXYGEN__)
+extern SPIDriver SPIDB0;
+#endif
+
+#if (MSP430X_SPI_USE_SPIB1 == TRUE) && !defined(__DOXYGEN__)
+extern SPIDriver SPIDB1;
+#endif
+
+#if (MSP430X_SPI_USE_SPIB2 == TRUE) && !defined(__DOXYGEN__)
+extern SPIDriver SPIDB2;
+#endif
+
+#if (MSP430X_SPI_USE_SPIB3 == TRUE) && !defined(__DOXYGEN__)
+extern SPIDriver SPIDB3;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void spi_lld_init(void);
+ void spi_lld_start(SPIDriver *spip);
+ void spi_lld_stop(SPIDriver *spip);
+ void spi_lld_select(SPIDriver *spip);
+ void spi_lld_unselect(SPIDriver *spip);
+ void spi_lld_ignore(SPIDriver *spip, size_t n);
+ void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf);
+ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
+ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
+ uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SPI == TRUE */
+
+#endif /* HAL_SPI_LLD_H */
+
+/** @} */
diff --git a/os/hal/ports/MSP430X/platform.mk b/os/hal/ports/MSP430X/platform.mk
index 6947785..832814b 100644
--- a/os/hal/ports/MSP430X/platform.mk
+++ b/os/hal/ports/MSP430X/platform.mk
@@ -3,7 +3,8 @@ PLATFORMSRC = ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_st_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_serial_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_pal_lld.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_dma_lld.c
+ ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_dma_lld.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_spi_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X
diff --git a/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h b/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h
index 4425d24..e5b62ee 100644
--- a/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h
+++ b/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h
@@ -38,18 +38,9 @@
#define TOTAL_GPIO_PADS 32
/**
- * @brief Generic I/O ports static initializer.
- * @details An instance of this structure must be passed to @p palInit() at
- * system startup time in order to initialized the digital I/O
- * subsystem. This represents only the initial setup, specific pads
- * or whole ports can be reprogrammed at later time.
- * @note Implementations may extend this structure to contain more,
- * architecture dependent, fields.
+ * @name Port related definitions
+ * @{
*/
-typedef struct {
- uint32_t pads[TOTAL_GPIO_PADS];
-} PALConfig;
-
/**
* @brief Width, in bits, of an I/O port.
*/
@@ -60,6 +51,50 @@ typedef struct {
* @brief This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFFU)
+/** @} */
+
+/**
+ * @name Line handling macros
+ * @{
+ */
+/**
+ * @brief Forms a line identifier.
+ * @details A port/pad pair are encoded into an @p ioline_t type. The encoding
+ * of this type is platform-dependent.
+ */
+#define PAL_LINE(port, pad) \
+ ((ioline_t)((uint32_t)(pad)))
+
+/**
+ * @brief Decodes a port identifier from a line identifier.
+ */
+#define PAL_PORT(line) \
+ ((ioportid_t)(IOPORT1))
+
+/**
+ * @brief Decodes a pad identifier from a line identifier.
+ */
+#define PAL_PAD(line) \
+ ((uint32_t)(line))
+
+/**
+ * @brief Value identifying an invalid line.
+ */
+#define PAL_NOLINE FFU
+/** @} */
+
+/**
+ * @brief Generic I/O ports static initializer.
+ * @details An instance of this structure must be passed to @p palInit() at
+ * system startup time in order to initialized the digital I/O
+ * subsystem. This represents only the initial setup, specific pads
+ * or whole ports can be reprogrammed at later time.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+typedef struct {
+ uint32_t pads[TOTAL_GPIO_PADS];
+} PALConfig;
/**
* @brief Digital I/O port sized unsigned type.
@@ -72,6 +107,11 @@ typedef uint32_t ioportmask_t;
typedef uint8_t iomode_t;
/**
+ * @brief Type of an I/O line.
+ */
+typedef uint32_t ioline_t;
+
+/**
* @brief Port Identifier.
* @details This type can be a scalar or some kind of pointer, do not make
* any assumption about it, use the provided macros when populating
@@ -266,7 +306,6 @@ typedef NRF_GPIO_Type *ioportid_t;
NRF_GPIO->OUTSET = 1 << (pad); \
} while (0)
-
/**
* @brief Pad mode setup.
* @details This function programs a pad with the specified mode.
diff --git a/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c b/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c
new file mode 100644
index 0000000..76bc572
--- /dev/null
+++ b/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c
@@ -0,0 +1,366 @@
+/*
+ ChibiOS/HAL - Copyright (C) 2016 Stéphane D'Alu
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_pwm_lld.c
+ * @brief NRF51 PWM subsystem low level driver source.
+ *
+ * @addtogroup PWM
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PWM || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief PWMD1 driver identifier.
+ * @note The driver PWMD1 allocates the timer TIMER0 when enabled.
+ */
+#if NRF51_PWM_USE_TIMER0 || defined(__DOXYGEN__)
+PWMDriver PWMD1;
+#endif
+
+/**
+ * @brief PWMD2 driver identifier.
+ * @note The driver PWMD2 allocates the timer TIMER1 when enabled.
+ */
+#if NRF51_PWM_USE_TIMER1 || defined(__DOXYGEN__)
+PWMDriver PWMD2;
+#endif
+
+/**
+ * @brief PWMD3 driver identifier.
+ * @note The driver PWMD3 allocates the timer TIMER2 when enabled.
+ */
+#if NRF51_PWM_USE_TIMER2 || defined(__DOXYGEN__)
+PWMDriver PWMD3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+static void pwm_lld_serve_interrupt(PWMDriver *pwmp) {
+ // Deal with PWM period
+ if (pwmp->timer->EVENTS_COMPARE[pwmp->channels]) {
+ pwmp->timer->EVENTS_COMPARE[pwmp->channels] = 0;
+
+ if (pwmp->config->callback != NULL) {
+ pwmp->config->callback(pwmp);
+ }
+ }
+
+ // Deal with PWM channels
+ uint8_t n;
+ for (n = 0 ; n < pwmp->channels ; n++) {
+ if (pwmp->timer->EVENTS_COMPARE[n]) {
+ pwmp->timer->EVENTS_COMPARE[n] = 0;
+ if (pwmp->config->channels[n].callback != NULL) {
+ pwmp->config->channels[n].callback(pwmp);
+ }
+ }
+ }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if NRF51_PWM_USE_TIMER0
+/**
+ * @brief TIMER0 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(Vector60) {
+ OSAL_IRQ_PROLOGUE();
+ pwm_lld_serve_interrupt(&PWMD1);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* NRF51_PWM_USE_TIMER0 */
+
+#if NRF51_PWM_USE_TIMER1
+/**
+ * @brief TIMER1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(Vector64) {
+ OSAL_IRQ_PROLOGUE();
+ pwm_lld_serve_interrupt(&PWMD2);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* NRF51_PWM_USE_TIMER1 */
+
+#if NRF51_PWM_USE_TIMER2
+/**
+ * @brief TIMER2 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(Vector68) {
+ OSAL_IRQ_PROLOGUE();
+ pwm_lld_serve_interrupt(&PWMD3);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* NRF51_PWM_USE_TIMER2 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level PWM driver initialization.
+ *
+ * @notapi
+ */
+void pwm_lld_init(void) {
+
+#if NRF51_PWM_USE_TIMER0
+ pwmObjectInit(&PWMD1);
+ PWMD1.channels = PWM_CHANNELS;
+ PWMD1.timer = NRF_TIMER0;
+#endif
+
+#if NRF51_PWM_USE_TIMER1
+ pwmObjectInit(&PWMD2);
+ PWMD2.channels = PWM_CHANNELS;
+ PWMD2.timer = NRF_TIMER1;
+#endif
+
+#if NRF51_PWM_USE_TIMER2
+ pwmObjectInit(&PWMD3);
+ PWMD3.channels = PWM_CHANNELS;
+ PWMD3.timer = NRF_TIMER2;
+#endif
+}
+
+/**
+ * @brief Configures and activates the PWM peripheral.
+ * @note Starting a driver that is already in the @p PWM_READY state
+ * disables all the active channels.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_start(PWMDriver *pwmp) {
+ // Prescaler value calculation: ftimer = 16MHz / 2^PRESCALER
+ uint16_t psc_ratio = NRF51_HFCLK_FREQUENCY / pwmp->config->frequency;
+ // Prescaler ratio must be between 1 and 512, and a power of two.
+ osalDbgAssert(psc_ratio <= 512 && !(psc_ratio & (psc_ratio - 1)),
+ "invalid frequency");
+ // Prescaler value as a power of 2, must be 0..9
+ uint32_t psc_value;
+ for (psc_value = 0; psc_value < 10; psc_value++)
+ if (psc_ratio == (unsigned)(1 << psc_value))
+ break;
+
+
+ // Configure as 16bits timer (only TIMER0 support 32bits)
+ pwmp->timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
+ pwmp->timer->MODE = TIMER_MODE_MODE_Timer;
+
+ // With clear shortcuts for period
+ pwmp->timer->SHORTS =
+ 0x1UL << (TIMER_SHORTS_COMPARE0_CLEAR_Pos + pwmp->channels);
+
+ // Disable and reset interrupts for compare events
+ pwmp->timer->INTENCLR = (TIMER_INTENCLR_COMPARE0_Msk |
+ TIMER_INTENCLR_COMPARE1_Msk |
+ TIMER_INTENCLR_COMPARE2_Msk |
+ TIMER_INTENCLR_COMPARE3_Msk );
+ pwmp->timer->EVENTS_COMPARE[0] = 0;
+ pwmp->timer->EVENTS_COMPARE[1] = 0;
+ pwmp->timer->EVENTS_COMPARE[2] = 0;
+ pwmp->timer->EVENTS_COMPARE[3] = 0;
+
+ // Set prescaler
+ pwmp->timer->PRESCALER = psc_value;
+
+ // Set period
+ pwmp->timer->CC[pwmp->channels] = pwmp->period;
+
+ // Clear everything
+ pwmp->timer->TASKS_CLEAR = 1;
+
+
+ // Enable interrupt
+#if NRF51_PWM_USE_TIMER0
+ if (&PWMD1 == pwmp) {
+ nvicEnableVector(TIMER0_IRQn, NRF51_PWM_TIMER0_PRIORITY);
+ }
+#endif
+
+#if NRF51_PWM_USE_TIMER1
+ if (&PWMD2 == pwmp) {
+ nvicEnableVector(TIMER1_IRQn, NRF51_PWM_TIMER1_PRIORITY);
+ }
+#endif
+
+#if NRF51_PWM_USE_TIMER2
+ if (&PWMD3 == pwmp) {
+ nvicEnableVector(TIMER2_IRQn, NRF51_PWM_TIMER2_PRIORITY);
+ }
+#endif
+
+ // Start timer
+ pwmp->timer->TASKS_START = 1;
+}
+
+/**
+ * @brief Deactivates the PWM peripheral.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_stop(PWMDriver *pwmp) {
+ pwmp->timer->TASKS_STOP = 1;
+
+#if NRF51_PWM_USE_TIMER0
+ if (&PWMD1 == pwmp) {
+ nvicDisableVector(TIMER0_IRQn);
+ }
+#endif
+
+#if NRF51_PWM_USE_TIMER1
+ if (&PWMD2 == pwmp) {
+ nvicDisableVector(TIMER1_IRQn);
+ }
+#endif
+
+#if NRF51_PWM_USE_TIMER2
+ if (&PWMD3 == pwmp) {
+ nvicDisableVector(TIMER2_IRQn);
+ }
+#endif
+}
+
+/**
+ * @brief Enables a PWM channel.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The channel is active using the specified configuration.
+ * @note The function has effect at the next cycle start.
+ * @note Channel notification is not enabled.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ * @param[in] width PWM pulse width as clock pulses number
+ *
+ * @notapi
+ */
+void pwm_lld_enable_channel(PWMDriver *pwmp,
+ pwmchannel_t channel,
+ pwmcnt_t width) {
+ pwmp->timer->CC[channel] = width;
+}
+
+/**
+ * @brief Disables a PWM channel and its notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The channel is disabled and its output line returned to the
+ * idle state.
+ * @note The function has effect at the next cycle start.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) {
+ pwmp->timer->CC[channel] = 0;
+}
+
+/**
+ * @brief Enables the periodic activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) {
+ pwmp->timer->INTENSET =
+ 0x1UL << (TIMER_INTENSET_COMPARE0_Pos + pwmp->channels);
+}
+
+/**
+ * @brief Disables the periodic activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) {
+ pwmp->timer->INTENCLR =
+ 0x1UL << (TIMER_INTENCLR_COMPARE0_Pos + pwmp->channels);
+}
+
+/**
+ * @brief Enables a channel de-activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @pre The channel must have been activated using @p pwmEnableChannel().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel) {
+ pwmp->timer->INTENSET =
+ 0x1UL << (TIMER_INTENSET_COMPARE0_Pos + channel);
+}
+
+/**
+ * @brief Disables a channel de-activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @pre The channel must have been activated using @p pwmEnableChannel().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel) {
+ pwmp->timer->INTENCLR =
+ 0x1UL << (TIMER_INTENCLR_COMPARE0_Pos + channel);
+}
+
+#endif /* HAL_USE_PWM */
+
+/** @} */
diff --git a/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h b/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h
new file mode 100644
index 0000000..0ddd65c
--- /dev/null
+++ b/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h
@@ -0,0 +1,276 @@
+/*
+ ChibiOS/HAL - Copyright (C) 2016 Stéphane D'Alu
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_pwm_lld.h
+ * @brief NRF51 PWM subsystem low level driver header.
+ *
+ * @addtogroup PWM
+ * @{
+ */
+
+#ifndef HAL_PWM_LLD_H_
+#define HAL_PWM_LLD_H_
+
+#if HAL_USE_PWM || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Number of PWM channels per PWM driver.
+ */
+#define PWM_CHANNELS 3
+
+
+#define PWM_FREQUENCY_16MHZ 16000000 /** @brief 16MHz */
+#define PWM_FREQUENCY_8MHZ 8000000 /** @brief 8MHz */
+#define PWM_FREQUENCY_4MHZ 4000000 /** @brief 4MHz */
+#define PWM_FREQUENCY_2MHZ 2000000 /** @brief 2MHz */
+#define PWM_FREQUENCY_1MHZ 1000000 /** @brief 1MHz */
+#define PWM_FREQUENCY_500KHZ 500000 /** @brief 500kHz */
+#define PWM_FREQUENCY_250KHZ 250000 /** @brief 250kHz */
+#define PWM_FREQUENCY_125KHZ 125000 /** @brief 125kHz */
+#define PWM_FREQUENCY_62500HZ 62500 /** @brief 62500Hz */
+#define PWM_FREQUENCY_31250HZ 31250 /** @brief 31250Hz */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+#if !defined(NRF51_PWM_USE_TIMER0)
+#define NRF51_PWM_USE_TIMER0 FALSE
+#endif
+
+#if !defined(NRF51_PWM_USE_TIMER1)
+#define NRF51_PWM_USE_TIMER1 FALSE
+#endif
+
+#if !defined(NRF51_PWM_USE_TIMER2)
+#define NRF51_PWM_USE_TIMER2 FALSE
+#endif
+
+/**
+ * @brief TIMER0 interrupt priority level setting.
+ */
+#if !defined(NRF51_PWM_TIMER0_PRIORITY) || defined(__DOXYGEN__)
+#define NRF51_PWM_TIMER0_PRIORITY 12
+#endif
+
+/**
+ * @brief TIMER1 interrupt priority level setting.
+ */
+#if !defined(NRF51_PWM_TIMER1_PRIORITY) || defined(__DOXYGEN__)
+#define NRF51_PWM_TIMER1_PRIORITY 12
+#endif
+
+/**
+ * @brief TIMER2 interrupt priority level setting.
+ */
+#if !defined(NRF51_PWM_TIMER2_PRIORITY) || defined(__DOXYGEN__)
+#define NRF51_PWM_TIMER2_PRIORITY 12
+#endif
+
+/** @} */
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/** @} */
+
+/*===========================================================================*/
+/* Configuration checks. */
+/*===========================================================================*/
+
+#if !NRF51_PWM_USE_TIMER0 && !NRF51_PWM_USE_TIMER1 && !NRF51_PWM_USE_TIMER2
+#error "PWM driver activated but no TIMER peripheral assigned"
+#endif
+
+#if (NRF51_ST_USE_TIMER0 == TRUE) && (NRF51_PWM_USE_TIMER0 == TRUE)
+#error "TIMER0 used for ST and PWM"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a PWM mode.
+ */
+typedef uint32_t pwmmode_t;
+
+/**
+ * @brief Type of a PWM channel.
+ */
+typedef uint8_t pwmchannel_t;
+
+/**
+ * @brief Type of a channels mask.
+ */
+typedef uint32_t pwmchnmsk_t;
+
+/**
+ * @brief Type of a PWM counter.
+ */
+typedef uint16_t pwmcnt_t;
+
+/**
+ * @brief Type of a PWM driver channel configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief Channel active logic level.
+ */
+ pwmmode_t mode;
+
+ /**
+ * @brief Channel callback pointer.
+ * @note This callback is invoked on the channel compare event. If set to
+ * @p NULL then the callback is disabled.
+ */
+ pwmcallback_t callback;
+ /* End of the mandatory fields.*/
+} PWMChannelConfig;
+
+/**
+ * @brief Type of a PWM driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief Timer clock in Hz.
+ * @note The low level can use assertions in order to catch invalid
+ * frequency specifications.
+ */
+ uint32_t frequency;
+ /**
+ * @brief PWM period in ticks.
+ * @note The low level can use assertions in order to catch invalid
+ * period specifications.
+ */
+ pwmcnt_t period;
+ /**
+ * @brief Periodic callback pointer.
+ * @note This callback is invoked on PWM counter reset. If set to
+ * @p NULL then the callback is disabled.
+ */
+ pwmcallback_t callback;
+ /**
+ * @brief Channels configurations.
+ */
+ PWMChannelConfig channels[PWM_CHANNELS];
+ /* End of the mandatory fields.*/
+} PWMConfig;
+
+/**
+ * @brief Structure representing a PWM driver.
+ */
+struct PWMDriver {
+ /**
+ * @brief Driver state.
+ */
+ pwmstate_t state;
+ /**
+ * @brief Current driver configuration data.
+ */
+ const PWMConfig *config;
+ /**
+ * @brief Current PWM period in ticks.
+ */
+ pwmcnt_t period;
+ /**
+ * @brief Mask of the enabled channels.
+ */
+ pwmchnmsk_t enabled;
+ /**
+ * @brief Number of channels in this instance.
+ */
+ pwmchannel_t channels;
+#if defined(PWM_DRIVER_EXT_FIELDS)
+ PWM_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the TIMER registers block.
+ */
+ NRF_TIMER_Type *timer;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Changes the period the PWM peripheral.
+ * @details This function changes the period of a PWM unit that has already
+ * been activated using @p pwmStart().
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The PWM unit period is changed to the new value.
+ * @note The function has effect at the next cycle start.
+ * @note If a period is specified that is shorter than the pulse width
+ * programmed in one of the channels then the behavior is not
+ * guaranteed.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] period new cycle time in ticks
+ *
+ * @notapi
+ */
+#define pwm_lld_change_period(pwmp, period) \
+ do { \
+ (pwmp)->timer->CC[(pwmp)->channels] = ((period) - 1); \
+ } while(0)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if NRF51_PWM_USE_TIMER0 || defined(__DOXYGEN__)
+extern PWMDriver PWMD1;
+#endif
+#if NRF51_PWM_USE_TIMER1 || defined(__DOXYGEN__)
+extern PWMDriver PWMD2;
+#endif
+#if NRF51_PWM_USE_TIMER2 || defined(__DOXYGEN__)
+extern PWMDriver PWMD3;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void pwm_lld_init(void);
+ void pwm_lld_start(PWMDriver *pwmp);
+ void pwm_lld_stop(PWMDriver *pwmp);
+ void pwm_lld_enable_channel(PWMDriver *pwmp,
+ pwmchannel_t channel,
+ pwmcnt_t width);
+ void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
+ void pwm_lld_enable_periodic_notification(PWMDriver *pwmp);
+ void pwm_lld_disable_periodic_notification(PWMDriver *pwmp);
+ void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel);
+ void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_PWM */
+
+#endif /* HAL_PWM_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/ports/NRF51/NRF51822/platform.mk b/os/hal/ports/NRF51/NRF51822/platform.mk
index fbe977e..b937e39 100644
--- a/os/hal/ports/NRF51/NRF51822/platform.mk
+++ b/os/hal/ports/NRF51/NRF51822/platform.mk
@@ -34,6 +34,9 @@ endif
ifneq ($(findstring HAL_USE_RNG TRUE,$(HALCONF)),)
PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_rng_lld.c
endif
+ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),)
+PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c
+endif
else
PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_lld.c \
@@ -47,7 +50,8 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_adc_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_gpt_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_wdg_lld.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_rng_lld.c
+ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_rng_lld.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c
endif
# Required include directories
diff --git a/testhal/KINETIS/FRDM-KL25Z/PWM/main.c b/testhal/KINETIS/FRDM-KL25Z/PWM/main.c
index b7e873c..32d8020 100644
--- a/testhal/KINETIS/FRDM-KL25Z/PWM/main.c
+++ b/testhal/KINETIS/FRDM-KL25Z/PWM/main.c
@@ -99,17 +99,17 @@ int main(void) {
/*
* Turn off the RGB LED.
*/
- palSetPad(GPIO_LED_RED, PIN_LED_RED); /* red */
- palSetPad(GPIO_LED_GREEN, PIN_LED_GREEN); /* green */
- palSetPad(GPIO_LED_BLUE, PIN_LED_BLUE); /* blue */
+ palSetLine(LINE_LED_RED); /* red */
+ palSetLine(LINE_LED_GREEN); /* green */
+ palSetLine(LINE_LED_BLUE); /* blue */
/*
* Start the PWM driver, route TPM2 output to PTB18, PTB19.
* Enable channels now to avoid a blink later.
*/
pwmStart(&PWM_DRIVER, &pwmcfg);
- palSetPadMode(GPIO_LED_RED, PIN_LED_RED, PAL_MODE_ALTERNATIVE_3);
- palSetPadMode(GPIO_LED_GREEN, PIN_LED_GREEN, PAL_MODE_ALTERNATIVE_3);
+ palSetLineMode(LINE_LED_RED, PAL_MODE_ALTERNATIVE_3);
+ palSetLineMode(LINE_LED_GREEN, PAL_MODE_ALTERNATIVE_3);
pwmEnableChannel(&PWM_DRIVER, 0, 0);
pwmEnableChannel(&PWM_DRIVER, 1, 0);
diff --git a/testhal/KINETIS/FRDM-KL26Z/PWM/main.c b/testhal/KINETIS/FRDM-KL26Z/PWM/main.c
index 9e41bf6..740471a 100644
--- a/testhal/KINETIS/FRDM-KL26Z/PWM/main.c
+++ b/testhal/KINETIS/FRDM-KL26Z/PWM/main.c
@@ -104,9 +104,9 @@ static THD_FUNCTION(ButtonThread, arg) {
uint8_t newstate, state = PAL_HIGH;
while(true) {
- if(palReadPad(GPIO_BUTTON, PIN_BUTTON) != state) {
+ if(palReadLine(LINE_BUTTON) != state) {
chThdSleepMilliseconds(20); /* debounce */
- newstate = palReadPad(GPIO_BUTTON, PIN_BUTTON);
+ newstate = palReadLine(LINE_BUTTON);
if(newstate != state) {
state = newstate;
if(newstate == PAL_LOW) {
@@ -135,9 +135,9 @@ int main(void) {
/*
* Turn off the RGB LED.
*/
- palSetPad(GPIO_LED_RED, PIN_LED_RED); /* red */
- palSetPad(GPIO_LED_GREEN, PIN_LED_GREEN); /* green */
- palSetPad(GPIO_LED_BLUE, PIN_LED_BLUE); /* blue */
+ palSetLine(LINE_LED_RED); /* red */
+ palSetLine(LINE_LED_GREEN); /* green */
+ palSetLine(LINE_LED_BLUE); /* blue */
/*
* Create the button check thread.
@@ -149,9 +149,9 @@ int main(void) {
* Enable channels now to avoid a blink later.
*/
pwmStart(&PWM_DRIVER, &pwmcfg);
- palSetPadMode(GPIO_LED_RED, PIN_LED_RED, PAL_MODE_ALTERNATIVE_3);
- palSetPadMode(GPIO_LED_GREEN, PIN_LED_GREEN, PAL_MODE_ALTERNATIVE_3);
- palSetPadMode(GPIO_LED_BLUE, PIN_LED_BLUE, PAL_MODE_ALTERNATIVE_4);
+ palSetLineMode(LINE_LED_RED, PAL_MODE_ALTERNATIVE_3);
+ palSetLineMode(LINE_LED_GREEN, PAL_MODE_ALTERNATIVE_3);
+ palSetLineMode(LINE_LED_BLUE, PAL_MODE_ALTERNATIVE_4);
pwmEnableChannel(&PWM_DRIVER, 2, 0);
pwmEnableChannel(&PWM_DRIVER, 4, 0);
pwmEnableChannel(&PWM_DRIVER, 5, 0);
diff --git a/testhal/KINETIS/MCHCK/PWM/main.c b/testhal/KINETIS/MCHCK/PWM/main.c
index 9ac569f..f92512e 100644
--- a/testhal/KINETIS/MCHCK/PWM/main.c
+++ b/testhal/KINETIS/MCHCK/PWM/main.c
@@ -19,12 +19,12 @@
static void pwmpcb(PWMDriver *pwmp) {
(void)pwmp;
- palSetPad(GPIOB, GPIOB_LED);
+ palSetLine(LINE_LED);
}
static void pwmc0cb(PWMDriver *pwmp) {
(void)pwmp;
- palClearPad(GPIOB, GPIOB_LED);
+ palClearLine(LINE_LED);
}
static PWMConfig pwmcfg = {
diff --git a/testhal/KINETIS/TEENSY_LC/PWM/main.c b/testhal/KINETIS/TEENSY_LC/PWM/main.c
index b366e9e..f8e6ba2 100644
--- a/testhal/KINETIS/TEENSY_LC/PWM/main.c
+++ b/testhal/KINETIS/TEENSY_LC/PWM/main.c
@@ -19,12 +19,12 @@
static void pwmpcb(PWMDriver *pwmp) {
(void)pwmp;
- palSetPad(TEENSY_PIN13_IOPORT, TEENSY_PIN13);
+ palSetLine(LINE_LED);
}
static void pwmc0cb(PWMDriver *pwmp) {
(void)pwmp;
- palClearPad(TEENSY_PIN13_IOPORT, TEENSY_PIN13);
+ palClearLine(LINE_LED);
}
static PWMConfig pwmcfg = {
diff --git a/testhal/MSP430X/EXP430FR5969/DMA/Makefile b/testhal/MSP430X/EXP430FR5969/DMA/Makefile
index e109c95..cf81f18 100644
--- a/testhal/MSP430X/EXP430FR5969/DMA/Makefile
+++ b/testhal/MSP430X/EXP430FR5969/DMA/Makefile
@@ -113,7 +113,6 @@ include $(CHIBIOS)/os/hal/osal/nil/osal.mk
include $(CHIBIOS)/os/nil/nil.mk
include $(CHIBIOS_CONTRIB)/os/common/ports/MSP430X/compilers/GCC/mk/port.mk
# Other files (optional).
-include $(CHIBIOS)/test/nil/test.mk
# Define linker script file here
LDSCRIPT = $(STARTUPLD)/msp430fr5969.ld
diff --git a/testhal/MSP430X/EXP430FR5969/DMA/main.c b/testhal/MSP430X/EXP430FR5969/DMA/main.c
index 96f45d0..1929af1 100644
--- a/testhal/MSP430X/EXP430FR5969/DMA/main.c
+++ b/testhal/MSP430X/EXP430FR5969/DMA/main.c
@@ -14,115 +14,119 @@
limitations under the License.
*/
-#include "hal.h"
#include "ch.h"
-#include "string.h"
+#include "hal.h"
#include "hal_dma_lld.h"
+#include "string.h"
const char * start_msg = "\r\n\r\nExecuting DMA test suite...\r\n";
-const char * test_1_msg = "TEST 1: Word-to-word memcpy with DMA engine, no callbacks\r\n";
-const char * test_2_msg = "TEST 2: Byte-to-byte memcpy with DMA engine, no callbacks\r\n";
-const char * test_3_msg = "TEST 3: Byte-to-byte memset with DMA engine, no callbacks\r\n";
-const char * test_4_msg = "TEST 4: Word-to-word memcpy with DMA engine, with callback\r\n";
-const char * test_5_msg = "TEST 5: Claim DMA channel 0, perform a Word-to-word memcpy\r\n";
-const char * test_6_msg = "TEST 6: Attempt to claim already claimed DMA channel, fail. Release it, try to claim it again, and succeed.\r\n";
-const char * test_7_msg = "TEST 7: Claim DMA channel 1, perform a Word-to-word memcpy, and release it\r\n";
+const char * test_1_msg =
+ "TEST 1: Word-to-word memcpy with DMA engine, no callbacks\r\n";
+const char * test_2_msg =
+ "TEST 2: Byte-to-byte memcpy with DMA engine, no callbacks\r\n";
+const char * test_3_msg =
+ "TEST 3: Byte-to-byte memset with DMA engine, no callbacks\r\n";
+const char * test_4_msg =
+ "TEST 4: Word-to-word memcpy with DMA engine, with callback\r\n";
+const char * test_5_msg =
+ "TEST 5: Claim DMA channel 0, perform a Word-to-word memcpy\r\n";
+const char * test_6_msg = "TEST 6: Attempt to claim already claimed DMA "
+ "channel, fail. Release it, try to claim it again, "
+ "and succeed.\r\n";
+const char * test_7_msg = "TEST 7: Claim DMA channel 1, perform a Word-to-word "
+ "memcpy, and release it\r\n";
const char * succeed_string = "SUCCESS\r\n\r\n";
-const char * fail_string = "FAILURE\r\n\r\n";
+const char * fail_string = "FAILURE\r\n\r\n";
-char instring[256];
+char instring[256];
char outstring[256];
-msp430x_dma_req_t *request;
+msp430x_dma_req_t * request;
uint8_t cb_arg = 1;
-void dma_callback_test(void* args) {
-
+void dma_callback_test(void * args) {
+
*((uint8_t *)args) = 0;
}
msp430x_dma_req_t test_1_req = {
- instring, /* source address */
- outstring, /* destination address */
- 9, /* number of words */
- MSP430X_DMA_SRCINCR | MSP430X_DMA_DSTINCR, /* address mode - dual increment */
- MSP430X_DMA_SRCWORD | MSP430X_DMA_DSTWORD, /* word transfer */
- MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
- DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
- {
+ instring, /* source address */
+ outstring, /* destination address */
+ 9, /* number of words */
+ MSP430X_DMA_SRCINCR | MSP430X_DMA_DSTINCR, /* address mode - dual increment */
+ MSP430X_DMA_SRCWORD | MSP430X_DMA_DSTWORD, /* word transfer */
+ MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
+ DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
+ {
NULL, /* no callback */
- NULL /* no arguments */
- }
+ NULL /* no arguments */
+ }
};
msp430x_dma_req_t test_2_req = {
- instring, /* source address */
- outstring, /* destination address */
- 18, /* number of bytes */
- MSP430X_DMA_SRCINCR | MSP430X_DMA_DSTINCR, /* address mode - dual increment */
- MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE, /* byte transfer */
- MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
- DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
- {
+ instring, /* source address */
+ outstring, /* destination address */
+ 18, /* number of bytes */
+ MSP430X_DMA_SRCINCR | MSP430X_DMA_DSTINCR, /* address mode - dual increment */
+ MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE, /* byte transfer */
+ MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
+ DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
+ {
NULL, /* no callback */
- NULL /* no arguments */
- }
+ NULL /* no arguments */
+ }
};
msp430x_dma_req_t test_3_req = {
- instring, /* source address */
- outstring, /* destination address */
- 16, /* number of words */
- MSP430X_DMA_DSTINCR, /* address mode - dest increment only */
- MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE, /* word transfer */
- MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
- DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
- {
+ instring, /* source address */
+ outstring, /* destination address */
+ 16, /* number of words */
+ MSP430X_DMA_DSTINCR, /* address mode - dest increment only */
+ MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE, /* word transfer */
+ MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
+ DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
+ {
NULL, /* no callback */
- NULL /* no arguments */
- }
+ NULL /* no arguments */
+ }
};
msp430x_dma_req_t test_4_req = {
- instring, /* source address */
- outstring, /* destination address */
- 9, /* number of words */
- MSP430X_DMA_SRCINCR | MSP430X_DMA_DSTINCR, /* address mode - dual increment */
- MSP430X_DMA_SRCWORD | MSP430X_DMA_DSTWORD, /* word transfer */
- MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
- DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
- {
+ instring, /* source address */
+ outstring, /* destination address */
+ 9, /* number of words */
+ MSP430X_DMA_SRCINCR | MSP430X_DMA_DSTINCR, /* address mode - dual increment */
+ MSP430X_DMA_SRCWORD | MSP430X_DMA_DSTWORD, /* word transfer */
+ MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
+ DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
+ {
&dma_callback_test, /* test callback */
- &cb_arg /* test arguments */
- }
+ &cb_arg /* test arguments */
+ }
};
msp430x_dma_req_t test_5_req = {
- instring, /* source address */
- outstring, /* destination address */
- 9, /* number of words */
- MSP430X_DMA_SRCINCR | MSP430X_DMA_DSTINCR, /* address mode - dual increment */
- MSP430X_DMA_SRCWORD | MSP430X_DMA_DSTWORD, /* word transfer */
- MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
- DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
- {
+ instring, /* source address */
+ outstring, /* destination address */
+ 9, /* number of words */
+ MSP430X_DMA_SRCINCR | MSP430X_DMA_DSTINCR, /* address mode - dual increment */
+ MSP430X_DMA_SRCWORD | MSP430X_DMA_DSTWORD, /* word transfer */
+ MSP430X_DMA_BLOCK, /* block (and blocking) transfer */
+ DMA_TRIGGER_MNEM(DMAREQ), /* software-requested trigger */
+ {
NULL, /* no callback */
- NULL /* no arguments */
- }
+ NULL /* no arguments */
+ }
};
-msp430x_dma_ch_t ch = {
- NULL,
- NULL,
- NULL
-};
+msp430x_dma_ch_t ch = { NULL, 0, NULL };
/*
* Thread 2.
*/
THD_WORKING_AREA(waThread1, 2048);
THD_FUNCTION(Thread1, arg) {
-
+
(void)arg;
/*
@@ -133,11 +137,11 @@ THD_FUNCTION(Thread1, arg) {
while (chnGetTimeout(&SD0, TIME_INFINITE)) {
chnWrite(&SD0, (const uint8_t *)start_msg, strlen(start_msg));
chThdSleepMilliseconds(2000);
-
+
/* Test 1 - use DMA engine to execute a word-wise memory-to-memory copy. */
chnWrite(&SD0, (const uint8_t *)test_1_msg, strlen(test_1_msg));
- strcpy( instring, "After DMA test \r\n" );
- strcpy( outstring, "Before DMA test \r\n");
+ strcpy(instring, "After DMA test \r\n");
+ strcpy(outstring, "Before DMA test \r\n");
if (strcmp("Before DMA test \r\n", outstring)) {
chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
}
@@ -149,11 +153,11 @@ THD_FUNCTION(Thread1, arg) {
else {
chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
}
-
+
/* Test 2 - use DMA engine to execute a byte-wise memory-to-memory copy. */
chnWrite(&SD0, (const uint8_t *)test_2_msg, strlen(test_2_msg));
- strcpy( instring, "After DMA test \r\n" );
- strcpy( outstring, "Before DMA test \r\n");
+ strcpy(instring, "After DMA test \r\n");
+ strcpy(outstring, "Before DMA test \r\n");
if (strcmp("Before DMA test \r\n", outstring)) {
chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
}
@@ -165,11 +169,11 @@ THD_FUNCTION(Thread1, arg) {
else {
chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
}
-
+
/* Test 3 - use DMA engine to execute a word-wise memory-to-memory set. */
chnWrite(&SD0, (const uint8_t *)test_3_msg, strlen(test_3_msg));
- strcpy( instring, "After DMA test \r\n" );
- strcpy( outstring, "Before DMA test \r\n");
+ strcpy(instring, "After DMA test \r\n");
+ strcpy(outstring, "Before DMA test \r\n");
if (strcmp("Before DMA test \r\n", outstring)) {
chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
}
@@ -181,12 +185,13 @@ THD_FUNCTION(Thread1, arg) {
else {
chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
}
-
- /* Test 4 - use DMA engine to execute a word-wise memory-to-memory copy,
+
+ /* Test 4 - use DMA engine to execute a word-wise memory-to-memory copy,
* then call a callback. */
chnWrite(&SD0, (const uint8_t *)test_4_msg, strlen(test_4_msg));
- strcpy( instring, "After DMA test \r\n" );
- strcpy( outstring, "Before DMA test \r\n");
+ strcpy(instring, "After DMA test \r\n");
+ strcpy(outstring, "Before DMA test \r\n");
+ cb_arg = 1;
if (strcmp("Before DMA test \r\n", outstring) || (cb_arg != 1)) {
chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
}
@@ -198,11 +203,12 @@ THD_FUNCTION(Thread1, arg) {
else {
chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
}
-
- /* Test 5 - use exclusive DMA channel 0 to execute a word-wise memory-to-memory copy. */
+
+ /* Test 5 - use exclusive DMA channel 0 to execute a word-wise
+ * memory-to-memory copy. */
chnWrite(&SD0, (const uint8_t *)test_5_msg, strlen(test_5_msg));
- strcpy( instring, "After DMA test \r\n" );
- strcpy( outstring, "Before DMA test \r\n");
+ strcpy(instring, "After DMA test \r\n");
+ strcpy(outstring, "Before DMA test \r\n");
if (strcmp("Before DMA test \r\n", outstring)) {
chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
}
@@ -215,8 +221,9 @@ THD_FUNCTION(Thread1, arg) {
else {
chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
}
-
- /* Test 6 - Attempt to claim DMA channel 0, fail, release it, attempt to claim it again */
+
+ /* Test 6 - Attempt to claim DMA channel 0, fail, release it, attempt to
+ * claim it again */
chnWrite(&SD0, (const uint8_t *)test_6_msg, strlen(test_6_msg));
if (!dmaAcquire(&ch, 0)) {
chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
@@ -229,11 +236,12 @@ THD_FUNCTION(Thread1, arg) {
chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
}
dmaRelease(&ch);
-
- /* Test 7 - use exclusive DMA channel 1 to execute a word-wise memory-to-memory copy. */
+
+ /* Test 7 - use exclusive DMA channel 1 to execute a word-wise
+ * memory-to-memory copy. */
chnWrite(&SD0, (const uint8_t *)test_7_msg, strlen(test_7_msg));
- strcpy( instring, "After DMA test \r\n" );
- strcpy( outstring, "Before DMA test \r\n");
+ strcpy(instring, "After DMA test \r\n");
+ strcpy(outstring, "Before DMA test \r\n");
if (strcmp("Before DMA test \r\n", outstring)) {
chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
}
@@ -250,7 +258,6 @@ THD_FUNCTION(Thread1, arg) {
}
}
-
/*
* Threads static table, one entry per thread. The number of entries must
* match NIL_CFG_NUM_THREADS.
@@ -272,12 +279,11 @@ int main(void) {
* RTOS is active.
*/
WDTCTL = WDTPW | WDTHOLD;
-
halInit();
chSysInit();
dmaInit();
-
+
/* This is now the idle thread loop, you may perform here a low priority
task but you must never try to sleep or wait in this loop. Note that
this tasks runs at the lowest priority level so any instruction added
diff --git a/testhal/MSP430X/EXP430FR5969/SPI/Makefile b/testhal/MSP430X/EXP430FR5969/SPI/Makefile
new file mode 100644
index 0000000..cf81f18
--- /dev/null
+++ b/testhal/MSP430X/EXP430FR5969/SPI/Makefile
@@ -0,0 +1,206 @@
+##############################################################################
+# Build global options
+# NOTE: Can be overridden externally.
+#
+
+# Optimization level, can be [0, 1, 2, 3, s].
+# 0 = turn off optimization. s = optimize for size.
+# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
+OPTIMIZE = 0
+
+# Debugging format.
+DEBUG =
+#DEBUG = stabs
+
+# Memory/data model
+MODEL = small
+
+# Object files directory
+# To put object files in current directory, use a dot (.), do NOT make
+# this an empty or blank macro!
+OBJDIR = .
+
+# Compiler flag to set the C Standard level.
+# c89 = "ANSI" C
+# gnu89 = c89 plus GCC extensions
+# c99 = ISO C99 standard (not yet fully implemented)
+# gnu99 = c99 plus GCC extensions
+CSTANDARD = -std=gnu11
+
+# Compiler options here.
+ifeq ($(USE_OPT),)
+ USE_OPT = -O$(OPTIMIZE) -g$(DEBUG)
+ USE_OPT += -funsigned-char -fshort-enums
+endif
+
+# C specific options here (added to USE_OPT).
+ifeq ($(USE_COPT),)
+ USE_COPT =
+endif
+
+# C++ specific options here (added to USE_OPT).
+ifeq ($(USE_CPPOPT),)
+ USE_CPPOPT = -fno-rtti
+endif
+
+# Enable this if you want the linker to remove unused code and data
+ifeq ($(USE_LINK_GC),)
+ USE_LINK_GC = yes
+endif
+
+# Linker extra options here.
+ifeq ($(USE_LDOPT),)
+ USE_LDOPT =
+endif
+
+# Enable this if you want link time optimizations (LTO)
+ifeq ($(USE_LTO),)
+ USE_LTO = no
+endif
+
+# Enable the selected hardware multiplier
+ifeq ($(USE_HWMULT),)
+ USE_HWMULT = f5series
+endif
+
+# Enable this if you want to see the full log while compiling.
+ifeq ($(USE_VERBOSE_COMPILE),)
+ USE_VERBOSE_COMPILE = yes
+endif
+
+# If enabled, this option makes the build process faster by not compiling
+# modules not used in the current configuration.
+ifeq ($(USE_SMART_BUILD),)
+ USE_SMART_BUILD = yes
+endif
+
+#
+# Build global options
+##############################################################################
+
+##############################################################################
+# Architecture or project specific options
+#
+
+# Stack size to be allocated to the idle thread stack. This stack is
+# the stack used by the main() thread.
+ifeq ($(USE_IDLE_STACKSIZE),)
+ USE_IDLE_STACKSIZE = 0xC00
+endif
+
+#
+# Architecture or project specific options
+##############################################################################
+
+##############################################################################
+# Project, sources and paths
+#
+
+# Define project name here
+PROJECT = nil
+
+# Imported source files and paths
+CHIBIOS = ../../../../../ChibiOS-RT
+CHIBIOS_CONTRIB = ../../../..
+# Startup files.
+include $(CHIBIOS_CONTRIB)/os/common/startup/MSP430X/compilers/GCC/mk/startup_msp430fr5xxx.mk
+# HAL-OSAL files (optional).
+include $(CHIBIOS)/os/hal/hal.mk
+include $(CHIBIOS_CONTRIB)/os/hal/boards/EXP430FR5969/board.mk
+include $(CHIBIOS_CONTRIB)/os/hal/ports/MSP430X/platform.mk
+include $(CHIBIOS)/os/hal/osal/nil/osal.mk
+# RTOS files (optional).
+include $(CHIBIOS)/os/nil/nil.mk
+include $(CHIBIOS_CONTRIB)/os/common/ports/MSP430X/compilers/GCC/mk/port.mk
+# Other files (optional).
+
+# Define linker script file here
+LDSCRIPT = $(STARTUPLD)/msp430fr5969.ld
+
+# C sources
+CSRC = $(STARTUPSRC) \
+ $(KERNSRC) \
+ $(PORTSRC) \
+ $(OSALSRC) \
+ $(HALSRC) \
+ $(PLATFORMSRC) \
+ $(BOARDSRC) \
+ $(TESTSRC) \
+ msp_vectors.c \
+ main.c
+
+# C++ sources
+CPPSRC =
+
+# List ASM source files here
+ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM)
+
+INCDIR = $(CHIBIOS)/os/license \
+ $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
+ $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
+ $(CHIBIOS)/os/various
+
+#
+# Project, sources and paths
+##############################################################################
+
+##############################################################################
+# Compiler settings
+#
+
+MCU = msp430fr5969
+
+TRGT = msp430-elf-
+CC = $(TRGT)gcc
+CPPC = $(TRGT)g++
+# Enable loading with g++ only if you need C++ runtime support.
+# NOTE: You can use C++ even without C++ support if you are careful. C++
+# runtime support makes code size explode.
+LD = $(TRGT)gcc
+#LD = $(TRGT)g++
+CP = $(TRGT)objcopy
+AS = $(TRGT)gcc -x assembler-with-cpp
+AR = $(TRGT)ar
+OD = $(TRGT)objdump
+SZ = $(TRGT)size
+HEX = $(CP) -O ihex
+BIN = $(CP) -O binary
+
+# MSP430-specific options here
+MOPT = -m$(MODEL)
+
+# Define C warning options here
+CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
+
+# Define C++ warning options here
+CPPWARN = -Wall -Wextra -Wundef
+
+#
+# Compiler settings
+##############################################################################
+
+##############################################################################
+# Start of user section
+#
+
+# List all user C define here, like -D_DEBUG=1
+UDEFS =
+
+# Define ASM defines here
+UADEFS =
+
+# List all user directories here
+UINCDIR =
+
+# List the user directory to look for the libraries here
+ULIBDIR =
+
+# List all user libraries here
+ULIBS =
+
+#
+# End of user defines
+##############################################################################
+
+RULESPATH = $(CHIBIOS_CONTRIB)/os/common/startup/MSP430X/compilers/GCC
+include $(RULESPATH)/rules.mk
diff --git a/testhal/MSP430X/EXP430FR5969/SPI/chconf.h b/testhal/MSP430X/EXP430FR5969/SPI/chconf.h
new file mode 100644
index 0000000..cb45526
--- /dev/null
+++ b/testhal/MSP430X/EXP430FR5969/SPI/chconf.h
@@ -0,0 +1,274 @@
+/*
+ ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file nilconf.h
+ * @brief Configuration file template.
+ * @details A copy of this file must be placed in each project directory, it
+ * contains the application specific kernel settings.
+ *
+ * @addtogroup config
+ * @details Kernel related settings and hooks.
+ * @{
+ */
+
+#ifndef CHCONF_H
+#define CHCONF_H
+
+#define _CHIBIOS_NIL_CONF_
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Number of user threads in the application.
+ * @note This number is not inclusive of the idle thread which is
+ * Implicitly handled.
+ */
+#define CH_CFG_NUM_THREADS 1
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name System timer settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief System time counter resolution.
+ * @note Allowed values are 16 or 32 bits.
+ */
+#define CH_CFG_ST_RESOLUTION 16
+
+/**
+ * @brief System tick frequency.
+ * @note This value together with the @p CH_CFG_ST_RESOLUTION
+ * option defines the maximum amount of time allowed for
+ * timeouts.
+ */
+#define CH_CFG_ST_FREQUENCY 1000
+
+/**
+ * @brief Time delta constant for the tick-less mode.
+ * @note If this value is zero then the system uses the classic
+ * periodic tick. This value represents the minimum number
+ * of ticks that is safe to specify in a timeout directive.
+ * The value one is not valid, timeouts are rounded up to
+ * this value.
+ */
+#define CH_CFG_ST_TIMEDELTA 0
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Subsystem options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Semaphores APIs.
+ * @details If enabled then the Semaphores APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_SEMAPHORES TRUE
+
+/**
+ * @brief Mutexes APIs.
+ * @details If enabled then the mutexes APIs are included in the kernel.
+ *
+ * @note Feature not currently implemented.
+ * @note The default is @p FALSE.
+ */
+#define CH_CFG_USE_MUTEXES FALSE
+
+/**
+ * @brief Events Flags APIs.
+ * @details If enabled then the event flags APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_EVENTS TRUE
+
+/**
+ * @brief Mailboxes APIs.
+ * @details If enabled then the asynchronous messages (mailboxes) APIs are
+ * included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_MAILBOXES TRUE
+
+/**
+ * @brief Core Memory Manager APIs.
+ * @details If enabled then the core memory manager APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMCORE TRUE
+
+/**
+ * @brief Heap Allocator APIs.
+ * @details If enabled then the memory heap allocator APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_HEAP TRUE
+
+/**
+ * @brief Memory Pools Allocator APIs.
+ * @details If enabled then the memory pools allocator APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMPOOLS TRUE
+
+/**
+ * @brief Managed RAM size.
+ * @details Size of the RAM area to be managed by the OS. If set to zero
+ * then the whole available RAM is used. The core memory is made
+ * available to the heap allocator and/or can be used directly through
+ * the simplified core memory allocator.
+ *
+ * @note In order to let the OS manage the whole RAM the linker script must
+ * provide the @p __heap_base__ and @p __heap_end__ symbols.
+ * @note Requires @p CH_CFG_USE_MEMCORE.
+ */
+#define CH_CFG_MEMCORE_SIZE 0
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Debug options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Debug option, kernel statistics.
+ *
+ * @note Feature not currently implemented.
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_STATISTICS FALSE
+
+/**
+ * @brief Debug option, system state check.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_SYSTEM_STATE_CHECK FALSE
+
+/**
+ * @brief Debug option, parameters checks.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_ENABLE_CHECKS FALSE
+
+/**
+ * @brief System assertions.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_ENABLE_ASSERTS FALSE
+
+/**
+ * @brief Stack check.
+ *
+ *@note The default is @p FALSE.
+ */
+#define CH_DBG_ENABLE_STACK_CHECK TRUE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel hooks
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief System initialization hook.
+ */
+#if !defined(CH_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__)
+#define CH_CFG_SYSTEM_INIT_HOOK() { \
+}
+#endif
+
+/**
+ * @brief Threads descriptor structure extension.
+ * @details User fields added to the end of the @p thread_t structure.
+ */
+#define CH_CFG_THREAD_EXT_FIELDS \
+ /* Add threads custom fields here.*/
+
+/**
+ * @brief Threads initialization hook.
+ */
+#define CH_CFG_THREAD_EXT_INIT_HOOK(tr) { \
+ /* Add custom threads initialization code here.*/ \
+}
+
+/**
+ * @brief Idle thread enter hook.
+ * @note This hook is invoked within a critical zone, no OS functions
+ * should be invoked from here.
+ * @note This macro can be used to activate a power saving mode.
+ */
+#define CH_CFG_IDLE_ENTER_HOOK() { \
+}
+
+/**
+ * @brief Idle thread leave hook.
+ * @note This hook is invoked within a critical zone, no OS functions
+ * should be invoked from here.
+ * @note This macro can be used to deactivate a power saving mode.
+ */
+#define CH_CFG_IDLE_LEAVE_HOOK() { \
+}
+
+/**
+ * @brief System halt hook.
+ */
+#if !defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
+#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \
+}
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/* Port-specific settings (override port settings defaulted in nilcore.h). */
+/*===========================================================================*/
+
+#endif /* _CHCONF_H_ */
+
+/** @} */
diff --git a/testhal/MSP430X/EXP430FR5969/SPI/halconf.h b/testhal/MSP430X/EXP430FR5969/SPI/halconf.h
new file mode 100644
index 0000000..083e124
--- /dev/null
+++ b/testhal/MSP430X/EXP430FR5969/SPI/halconf.h
@@ -0,0 +1,388 @@
+/*
+ ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file templates/halconf.h
+ * @brief HAL configuration header.
+ * @details HAL configuration file, this file allows to enable or disable the
+ * various device drivers from your application. You may also use
+ * this file in order to override the device drivers default settings.
+ *
+ * @addtogroup HAL_CONF
+ * @{
+ */
+
+#ifndef HALCONF_H
+#define HALCONF_H
+
+#include "mcuconf.h"
+
+/**
+ * @brief Enables the PAL subsystem.
+ */
+#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
+#define HAL_USE_PAL TRUE
+#endif
+
+/**
+ * @brief Enables the DMA subsystem.
+ */
+#if !defined(HAL_USE_DMA) || defined(__DOXYGEN__)
+#define HAL_USE_DMA TRUE
+#endif
+
+/**
+ * @brief Enables the ADC subsystem.
+ */
+#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
+#define HAL_USE_ADC FALSE
+#endif
+
+/**
+ * @brief Enables the DAC subsystem.
+ */
+#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
+#define HAL_USE_DAC FALSE
+#endif
+
+/**
+ * @brief Enables the CAN subsystem.
+ */
+#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
+#define HAL_USE_CAN FALSE
+#endif
+
+/**
+ * @brief Enables the EXT subsystem.
+ */
+#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
+#define HAL_USE_EXT FALSE
+#endif
+
+/**
+ * @brief Enables the GPT subsystem.
+ */
+#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
+#define HAL_USE_GPT FALSE
+#endif
+
+/**
+ * @brief Enables the I2C subsystem.
+ */
+#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
+#define HAL_USE_I2C FALSE
+#endif
+
+/**
+ * @brief Enables the I2S subsystem.
+ */
+#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
+#define HAL_USE_I2S FALSE
+#endif
+
+/**
+ * @brief Enables the ICU subsystem.
+ */
+#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
+#define HAL_USE_ICU FALSE
+#endif
+
+/**
+ * @brief Enables the MAC subsystem.
+ */
+#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
+#define HAL_USE_MAC FALSE
+#endif
+
+/**
+ * @brief Enables the MMC_SPI subsystem.
+ */
+#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_MMC_SPI FALSE
+#endif
+
+/**
+ * @brief Enables the PWM subsystem.
+ */
+#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
+#define HAL_USE_PWM FALSE
+#endif
+
+/**
+ * @brief Enables the RTC subsystem.
+ */
+#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
+#define HAL_USE_RTC FALSE
+#endif
+
+/**
+ * @brief Enables the SDC subsystem.
+ */
+#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
+#define HAL_USE_SDC FALSE
+#endif
+
+/**
+ * @brief Enables the SERIAL subsystem.
+ */
+#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL TRUE
+#endif
+
+/**
+ * @brief Enables the SERIAL over USB subsystem.
+ */
+#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL_USB FALSE
+#endif
+
+/**
+ * @brief Enables the SPI subsystem.
+ */
+#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_SPI TRUE
+#endif
+
+/**
+ * @brief Enables the UART subsystem.
+ */
+#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
+#define HAL_USE_UART FALSE
+#endif
+
+/**
+ * @brief Enables the USB subsystem.
+ */
+#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
+#define HAL_USE_USB FALSE
+#endif
+
+/**
+ * @brief Enables the WDG subsystem.
+ */
+#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
+#define HAL_USE_WDG FALSE
+#endif
+
+/*===========================================================================*/
+/* ADC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
+#define ADC_USE_WAIT FALSE
+#endif
+
+/**
+ * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define ADC_USE_MUTUAL_EXCLUSION FALSE
+#endif
+
+/*===========================================================================*/
+/* CAN driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Sleep mode related APIs inclusion switch.
+ */
+#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
+#define CAN_USE_SLEEP_MODE FALSE
+#endif
+
+/*===========================================================================*/
+/* I2C driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the mutual exclusion APIs on the I2C bus.
+ */
+#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define I2C_USE_MUTUAL_EXCLUSION FALSE
+#endif
+
+/*===========================================================================*/
+/* MAC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
+#define MAC_USE_ZERO_COPY FALSE
+#endif
+
+/**
+ * @brief Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
+#define MAC_USE_EVENTS FALSE
+#endif
+
+/*===========================================================================*/
+/* MMC_SPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ * routines releasing some extra CPU time for the threads with
+ * lower priority, this may slow down the driver a bit however.
+ * This option is recommended also if the SPI driver does not
+ * use a DMA channel and heavily loads the CPU.
+ */
+#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
+#define MMC_NICE_WAITING FALSE
+#endif
+
+/*===========================================================================*/
+/* SDC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Number of initialization attempts before rejecting the card.
+ * @note Attempts are performed at 10mS intervals.
+ */
+#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
+#define SDC_INIT_RETRY 100
+#endif
+
+/**
+ * @brief Include support for MMC cards.
+ * @note MMC support is not yet implemented so this option must be kept
+ * at @p FALSE.
+ */
+#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
+#define SDC_MMC_SUPPORT FALSE
+#endif
+
+/**
+ * @brief Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ * routines releasing some extra CPU time for the threads with
+ * lower priority, this may slow down the driver a bit however.
+ */
+#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
+#define SDC_NICE_WAITING FALSE
+#endif
+
+/*===========================================================================*/
+/* SERIAL driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Default bit rate.
+ * @details Configuration parameter, this is the baud rate selected for the
+ * default configuration.
+ */
+#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
+#define SERIAL_DEFAULT_BITRATE 38400
+#endif
+
+/**
+ * @brief Serial buffers size.
+ * @details Configuration parameter, you can change the depth of the queue
+ * buffers depending on the requirements of your application.
+ * @note The default is 16 bytes for both the transmission and receive
+ * buffers.
+ */
+#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_BUFFERS_SIZE 16
+#endif
+
+/*===========================================================================*/
+/* SERIAL_USB driver related setting. */
+/*===========================================================================*/
+
+/**
+ * @brief Serial over USB buffers size.
+ * @details Configuration parameter, the buffer size must be a multiple of
+ * the USB data endpoint maximum packet size.
+ * @note The default is 256 bytes for both the transmission and receive
+ * buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_SIZE 256
+#endif
+
+/**
+ * @brief Serial over USB number of buffers.
+ * @note The default is 2 buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_NUMBER 2
+#endif
+
+/*===========================================================================*/
+/* SPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
+#define SPI_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define SPI_USE_MUTUAL_EXCLUSION FALSE
+#endif
+
+/*===========================================================================*/
+/* UART driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
+#define UART_USE_WAIT FALSE
+#endif
+
+/**
+ * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define UART_USE_MUTUAL_EXCLUSION FALSE
+#endif
+
+/*===========================================================================*/
+/* USB driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
+#define USB_USE_WAIT FALSE
+#endif
+
+#endif /* _HALCONF_H_ */
+
+/** @} */
diff --git a/testhal/MSP430X/EXP430FR5969/SPI/main.c b/testhal/MSP430X/EXP430FR5969/SPI/main.c
new file mode 100644
index 0000000..17f5c86
--- /dev/null
+++ b/testhal/MSP430X/EXP430FR5969/SPI/main.c
@@ -0,0 +1,395 @@
+/*
+ ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "ch.h"
+#include "hal.h"
+#include "hal_dma_lld.h"
+#include "string.h"
+
+/* Disable watchdog because of lousy startup code in newlib */
+static void __attribute__((naked, section(".crt_0042disable_watchdog"), used))
+disable_watchdog(void) {
+ WDTCTL = WDTPW | WDTHOLD;
+}
+
+const char * start_msg = "\r\n\r\nExecuting SPI test suite...\r\n";
+const char * test_1_msg = "TEST 1: spiStartIgnore, with callback\r\n";
+const char * test_2_msg = "TEST 2: spiStartExchange, with callback\r\n";
+const char * test_3_msg = "TEST 3: spiStartSend, with callback\r\n";
+const char * test_4_msg = "TEST 4: spiStartReceive, with callback\r\n";
+const char * test_5_msg = "TEST 5: spiIgnore\r\n";
+const char * test_6_msg = "TEST 6: spiExchange\r\n";
+const char * test_7_msg = "TEST 7: spiSend\r\n";
+const char * test_8_msg = "TEST 8: spiReceive\r\n";
+const char * test_9_msg = "TEST 9: spiStartExchange with exclusive DMA\r\n";
+const char * test_10_msg =
+ "TEST 10: spiStartExchange with exclusive DMA for TX\r\n";
+const char * test_11_msg =
+ "TEST 11: spiStartExchange with exclusive DMA for RX\r\n";
+
+const char * succeed_string = "SUCCESS\r\n\r\n";
+const char * fail_string = "FAILURE\r\n\r\n";
+
+char instring[256];
+char outstring[256];
+uint8_t cb_arg = 1;
+
+void spi_callback(SPIDriver * spip) {
+ (void)spip;
+ cb_arg = 0;
+}
+
+SPIConfig SPIDA1_config = {
+ spi_callback, /* callback */
+ PAL_NOLINE, /* hardware slave select line */
+ 250000, /* data rate */
+ MSP430X_SPI_BO_LSB, /* bit order */
+ MSP430X_SPI_DS_EIGHT, /* data size */
+ 0, /* SPI mode */
+ 0xFFU, /* no exclusive TX DMA */
+ 0xFFU /* no exclusive RX DMA */
+};
+
+SPIConfig SPIDB0_config = {
+ NULL, /* callback */
+ LINE_LED_G, /* GPIO slave select line */
+ 1000, /* data rate */
+ MSP430X_SPI_BO_MSB, /* bit order */
+ MSP430X_SPI_DS_SEVEN, /* data size */
+ 3, /* SPI mode */
+ 0xFF, /* no exclusive TX DMA */
+ 0xFF /* no exclusive RX DMA */
+};
+
+/*
+ * Thread 2.
+ */
+THD_WORKING_AREA(waThread1, 4096);
+THD_FUNCTION(Thread1, arg) {
+
+ (void)arg;
+
+ /* Set up loopback mode for testing */
+ SPIDA1.regs->statw_a |= UCLISTEN;
+ SPIDB0.regs->statw_b |= UCLISTEN;
+
+ /*
+ * Activate the serial driver 0 using the driver default configuration.
+ */
+ sdStart(&SD0, NULL);
+
+ /* Activate the SPI driver A1 using its config */
+ spiStart(&SPIDA1, &SPIDA1_config);
+ /* Activate the SPI driver B0 using its config */
+ spiStart(&SPIDB0, &SPIDB0_config);
+
+ while (chnGetTimeout(&SD0, TIME_INFINITE)) {
+ chnWrite(&SD0, (const uint8_t *)start_msg, strlen(start_msg));
+ chThdSleepMilliseconds(2000);
+
+ /* Test 1 - spiStartIgnore with callback */
+ chnWrite(&SD0, (const uint8_t *)test_1_msg, strlen(test_1_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ cb_arg = 1;
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 1) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDA1);
+ spiStartIgnore(&SPIDA1, strlen(outstring));
+ while (SPIDA1.state != SPI_READY)
+ ; /* wait for transaction to finish */
+ spiUnselect(&SPIDA1);
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 0) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Test 2 - spiStartExchange with callback */
+ chnWrite(&SD0, (const uint8_t *)test_2_msg, strlen(test_2_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ cb_arg = 1;
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 1) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDA1);
+ spiStartExchange(&SPIDA1, strlen(instring), outstring, instring);
+ while (SPIDA1.state != SPI_READY)
+ ; /* wait for transaction to finish */
+ spiUnselect(&SPIDA1);
+ if (strcmp("After SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 0) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Test 3 - spiStartSend with callback */
+ chnWrite(&SD0, (const uint8_t *)test_3_msg, strlen(test_3_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ cb_arg = 1;
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 1) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDA1);
+ spiStartSend(&SPIDA1, strlen(outstring), outstring);
+ while (SPIDA1.state != SPI_READY)
+ ; /* wait for transaction to finish */
+ spiUnselect(&SPIDA1);
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 0) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Test 4 - spiStartReceive with callback */
+ chnWrite(&SD0, (const uint8_t *)test_4_msg, strlen(test_4_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ cb_arg = 1;
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 1) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDA1);
+ chThdSleepMilliseconds(2000);
+ spiStartReceive(&SPIDA1, strlen(instring), instring);
+ while (SPIDA1.state != SPI_READY)
+ ; /* wait for transaction to finish */
+ spiUnselect(&SPIDA1);
+ if (strcmp("After SPI test \r\n", outstring) ||
+ strcmp("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff",
+ instring) ||
+ cb_arg != 0) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Test 5 - spiIgnore */
+ chnWrite(&SD0, (const uint8_t *)test_5_msg, strlen(test_5_msg));
+ strcpy(instring, "After SPI test \r\n");
+ strcpy(outstring, "Before SPI test \r\n");
+ if (strcmp("Before SPI test \r\n", outstring) ||
+ strcmp("After SPI test \r\n", instring)) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDB0);
+ chThdSleepMilliseconds(2000);
+ spiIgnore(&SPIDB0, strlen(outstring));
+ spiUnselect(&SPIDB0);
+ if (strcmp("After SPI test \r\n", instring) ||
+ strcmp("Before SPI test \r\n", outstring)) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Test 6 - spiExchange */
+ chnWrite(&SD0, (const uint8_t *)test_6_msg, strlen(test_6_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring)) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDB0);
+ spiExchange(&SPIDB0, strlen(outstring), outstring, instring);
+ spiUnselect(&SPIDB0);
+ if (strcmp("After SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring)) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Test 7 - spiSend */
+ chnWrite(&SD0, (const uint8_t *)test_7_msg, strlen(test_7_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring)) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDB0);
+ spiSend(&SPIDB0, strlen(outstring), outstring);
+ spiUnselect(&SPIDB0);
+ if (strcmp("After SPI test \r\n", outstring) ||
+ strcmp("Before SPI test \r\n", instring)) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Test 8 - spiReceive */
+ chnWrite(&SD0, (const uint8_t *)test_8_msg, strlen(test_8_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring)) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDB0);
+ spiReceive(&SPIDB0, strlen(instring), instring);
+ spiUnselect(&SPIDB0);
+ if (strcmp("After SPI test \r\n", outstring) ||
+ strcmp("\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f"
+ "\x7f\x7f\x7f",
+ instring)) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Reconfigure SPIDA1 to use exclusive DMA for both */
+ spiStop(&SPIDA1);
+ SPIDA1_config.dmatx_index = 0;
+ SPIDA1_config.dmarx_index = 1;
+ SPIDA1_config.spi_mode = 1; /* because why not get coverage */
+ spiStart(&SPIDA1, &SPIDA1_config);
+
+ /* Test 9 - spiStartExchange with exclusive DMA */
+ chnWrite(&SD0, (const uint8_t *)test_9_msg, strlen(test_9_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ cb_arg = 1;
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 1) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDA1);
+ spiStartExchange(&SPIDA1, strlen(outstring), outstring, instring);
+ while (SPIDA1.state != SPI_READY)
+ ; /* wait for transaction to finish */
+ spiUnselect(&SPIDA1);
+ if (strcmp("After SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 0) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Reconfigure SPIDA1 to use exclusive DMA for TX only */
+ spiStop(&SPIDA1);
+ SPIDA1_config.dmatx_index = 0;
+ SPIDA1_config.dmarx_index = 0xFFU;
+ SPIDA1_config.spi_mode = 2; /* because why not get coverage */
+ spiStart(&SPIDA1, &SPIDA1_config);
+
+ /* Test 10 - spiStartExchange with exclusive DMA for TX */
+ chnWrite(&SD0, (const uint8_t *)test_10_msg, strlen(test_10_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ cb_arg = 1;
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 1) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDA1);
+ spiStartExchange(&SPIDA1, strlen(outstring), outstring, instring);
+ while (SPIDA1.state != SPI_READY)
+ ; /* wait for transaction to finish */
+ spiUnselect(&SPIDA1);
+ if (strcmp("After SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 0) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+
+ /* Reconfigure SPIDA1 to use exclusive DMA for TX only */
+ spiStop(&SPIDA1);
+ SPIDA1_config.dmatx_index = 0xFFU;
+ SPIDA1_config.dmarx_index = 1;
+ SPIDA1_config.spi_mode = 3; /* because why not get coverage */
+ spiStart(&SPIDA1, &SPIDA1_config);
+
+ /* Test 11 - spiStartExchange with exclusive DMA for RX */
+ chnWrite(&SD0, (const uint8_t *)test_11_msg, strlen(test_11_msg));
+ strcpy(outstring, "After SPI test \r\n");
+ strcpy(instring, "Before SPI test \r\n");
+ cb_arg = 1;
+ if (strcmp("Before SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 1) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ spiSelect(&SPIDA1);
+ spiStartExchange(&SPIDA1, strlen(outstring), outstring, instring);
+ while (SPIDA1.state != SPI_READY)
+ ; /* wait for transaction to finish */
+ spiUnselect(&SPIDA1);
+ if (strcmp("After SPI test \r\n", instring) ||
+ strcmp("After SPI test \r\n", outstring) || cb_arg != 0) {
+ chnWrite(&SD0, (const uint8_t *)fail_string, strlen(fail_string));
+ }
+ else {
+ chnWrite(&SD0, (const uint8_t *)succeed_string, strlen(succeed_string));
+ }
+ }
+}
+
+/*
+ * Threads static table, one entry per thread. The number of entries must
+ * match NIL_CFG_NUM_THREADS.
+ */
+THD_TABLE_BEGIN
+ THD_TABLE_ENTRY(waThread1, "spi_test", Thread1, NULL)
+THD_TABLE_END
+
+/*
+ * Application entry point.
+ */
+int main(void) {
+
+ /*
+ * System initializations.
+ * - HAL initialization, this also initializes the configured device drivers
+ * and performs the board-specific initializations.
+ * - Kernel initialization, the main() function becomes a thread and the
+ * RTOS is active.
+ */
+ WDTCTL = WDTPW | WDTHOLD;
+
+ halInit();
+ chSysInit();
+ dmaInit();
+
+ /* This is now the idle thread loop, you may perform here a low priority
+ task but you must never try to sleep or wait in this loop. Note that
+ this tasks runs at the lowest priority level so any instruction added
+ here will be executed after all other tasks have been started.*/
+ while (true) {
+ }
+}
diff --git a/testhal/MSP430X/EXP430FR5969/SPI/mcuconf.h b/testhal/MSP430X/EXP430FR5969/SPI/mcuconf.h
new file mode 100644
index 0000000..5cacf76
--- /dev/null
+++ b/testhal/MSP430X/EXP430FR5969/SPI/mcuconf.h
@@ -0,0 +1,62 @@
+/*
+ ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef MCUCONF_H
+#define MCUCONF_H
+
+/*
+ * MSP430X drivers configuration.
+ * The following settings override the default settings present in
+ * the various device driver implementation headers.
+ * Note that the settings for each driver only have effect if the driver
+ * is enabled in halconf.h.
+ *
+ */
+
+#define MSP430X_MCUCONF
+
+/* HAL driver system settings */
+#define MSP430X_ACLK_SRC MSP430X_VLOCLK
+#define MSP430X_LFXTCLK_FREQ 0
+#define MSP430X_HFXTCLK_FREQ 0
+#define MSP430X_DCOCLK_FREQ 8000000
+#define MSP430X_MCLK_DIV 1
+#define MSP430X_SMCLK_DIV 32
+
+/*
+ * SERIAL driver system settings.
+ */
+#define MSP430X_SERIAL_USE_USART0 TRUE
+#define MSP430X_USART0_CLK_SRC MSP430X_SMCLK_SRC
+#define MSP430X_SERIAL_USE_USART1 FALSE
+#define MSP430X_SERIAL_USE_USART2 FALSE
+#define MSP430X_SERIAL_USE_USART3 FALSE
+
+/*
+ * ST driver system settings.
+ */
+#define MSP430X_ST_CLK_SRC MSP430X_SMCLK_SRC
+#define MSP430X_ST_TIMER_TYPE B
+#define MSP430X_ST_TIMER_INDEX 0
+
+/*
+ * SPI driver system settings.
+ */
+#define MSP430X_SPI_USE_SPIA1 TRUE
+#define MSP430X_SPI_USE_SPIB0 TRUE
+#define MSP430X_SPI_EXCLUSIVE_DMA TRUE
+
+#endif /* _MCUCONF_H_ */
diff --git a/testhal/MSP430X/EXP430FR5969/SPI/msp_vectors.c b/testhal/MSP430X/EXP430FR5969/SPI/msp_vectors.c
new file mode 100644
index 0000000..8968fb9
--- /dev/null
+++ b/testhal/MSP430X/EXP430FR5969/SPI/msp_vectors.c
@@ -0,0 +1,316 @@
+#include <msp430.h>
+
+__attribute__((interrupt(1)))
+void Vector1(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(2)))
+void Vector2(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(3)))
+void Vector3(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(4)))
+void Vector4(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(5)))
+void Vector5(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(6)))
+void Vector6(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(7)))
+void Vector7(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(8)))
+void Vector8(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(9)))
+void Vector9(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(10)))
+void Vector10(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(11)))
+void Vector11(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(12)))
+void Vector12(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(13)))
+void Vector13(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(14)))
+void Vector14(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(15)))
+void Vector15(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(16)))
+void Vector16(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(17)))
+void Vector17(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(18)))
+void Vector18(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(19)))
+void Vector19(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(20)))
+void Vector20(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(21)))
+void Vector21(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(22)))
+void Vector22(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(23)))
+void Vector23(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(24)))
+void Vector24(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(25)))
+void Vector25(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(26)))
+void Vector26(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(27)))
+void Vector27(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(28)))
+void Vector28(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(29)))
+void Vector29(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(30)))
+void Vector30(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(31)))
+void Vector31(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(32)))
+void Vector32(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(33)))
+void Vector33(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(34)))
+void Vector34(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(35)))
+void Vector35(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(36)))
+void Vector36(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(37)))
+void Vector37(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(38)))
+void Vector38(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(39)))
+void Vector39(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(40)))
+void Vector40(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(41)))
+void Vector41(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(42)))
+void Vector42(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(44)))
+void Vector44(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(45)))
+void Vector45(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(46)))
+void Vector46(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(47)))
+void Vector47(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(48)))
+void Vector48(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(50)))
+void Vector50(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(51)))
+void Vector51(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(53)))
+void Vector53(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(54)))
+void Vector54(void) {
+
+ while (1) {
+ }
+}
+__attribute__((interrupt(55)))
+void Vector55(void) {
+
+ while (1) {
+ }
+}
+
+
diff --git a/testhal/NRF51/NRF51822/PWM/Makefile b/testhal/NRF51/NRF51822/PWM/Makefile
new file mode 100644
index 0000000..6119c51
--- /dev/null
+++ b/testhal/NRF51/NRF51822/PWM/Makefile
@@ -0,0 +1,232 @@
+##############################################################################
+# Build global options
+# NOTE: Can be overridden externally.
+#
+
+# Compiler options here.
+ifeq ($(USE_OPT),)
+ USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
+endif
+
+# C specific options here (added to USE_OPT).
+ifeq ($(USE_COPT),)
+ USE_COPT =
+endif
+
+# C++ specific options here (added to USE_OPT).
+ifeq ($(USE_CPPOPT),)
+ USE_CPPOPT = -fno-rtti
+endif
+
+# Enable this if you want the linker to remove unused code and data
+ifeq ($(USE_LINK_GC),)
+ USE_LINK_GC = yes
+endif
+
+# Linker extra options here.
+ifeq ($(USE_LDOPT),)
+ USE_LDOPT =
+endif
+
+# Enable this if you want link time optimizations (LTO)
+ifeq ($(USE_LTO),)
+ USE_LTO = yes
+endif
+
+# If enabled, this option allows to compile the application in THUMB mode.
+ifeq ($(USE_THUMB),)
+ USE_THUMB = yes
+endif
+
+# Enable this if you want to see the full log while compiling.
+ifeq ($(USE_VERBOSE_COMPILE),)
+ USE_VERBOSE_COMPILE = no
+endif
+
+# If enabled, this option makes the build process faster by not compiling
+# modules not used in the current configuration.
+ifeq ($(USE_SMART_BUILD),)
+ USE_SMART_BUILD = yes
+endif
+
+#
+# Build global options
+##############################################################################
+
+##############################################################################
+# Architecture or project specific options
+#
+
+# Stack size to be allocated to the Cortex-M process stack. This stack is
+# the stack used by the main() thread.
+ifeq ($(USE_PROCESS_STACKSIZE),)
+ USE_PROCESS_STACKSIZE = 0x200
+endif
+
+# Stack size to the allocated to the Cortex-M main/exceptions stack. This
+# stack is used for processing interrupts and exceptions.
+ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
+ USE_EXCEPTIONS_STACKSIZE = 0x400
+endif
+
+# Enables the use of FPU on Cortex-M4 (no, softfp, hard).
+ifeq ($(USE_FPU),)
+ USE_FPU = no
+endif
+
+#
+# Architecture or project specific options
+##############################################################################
+
+##############################################################################
+# Project, sources and paths
+#
+
+# Define project name here
+PROJECT = ch
+
+# Imported source files and paths
+CHIBIOS = ../../../../ChibiOS-RT
+CHIBIOS_CONTRIB = $(CHIBIOS)/../ChibiOS-Contrib
+CHIBIOS = /home/sdalu/ChibiOS/ChibiOS
+CHIBIOS_CONTRIB = /home/sdalu/ChibiOS/ChibiOS-Contrib
+
+# Startup files.
+include $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_nrf51.mk
+# HAL-OSAL files (optional).
+include $(CHIBIOS)/os/hal/hal.mk
+include $(CHIBIOS_CONTRIB)/os/hal/ports/NRF51/NRF51822/platform.mk
+include $(CHIBIOS_CONTRIB)/os/hal/boards/WVSHARE_BLE400/board.mk
+include $(CHIBIOS)/os/hal/osal/rt/osal.mk
+# RTOS files (optional).
+include $(CHIBIOS)/os/rt/rt.mk
+include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v6m.mk
+# Other files (optional).
+include $(CHIBIOS)/test/rt/test.mk
+
+# Define linker script file here
+LDSCRIPT= $(STARTUPLD)/NRF51822.ld
+
+# C sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CSRC = $(STARTUPSRC) \
+ $(KERNSRC) \
+ $(PORTSRC) \
+ $(OSALSRC) \
+ $(HALSRC) \
+ $(PLATFORMSRC) \
+ $(BOARDSRC) \
+ main.c
+
+# C++ sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CPPSRC =
+
+# C sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+# option that results in lower performance and larger code size.
+ACSRC =
+
+# C++ sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+# option that results in lower performance and larger code size.
+ACPPSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+# option that results in lower performance and larger code size.
+TCSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+# option that results in lower performance and larger code size.
+TCPPSRC =
+
+# List ASM source files here
+ASMSRC =
+ASMXSRC = $(STARTUPASM) $(PORTASM) $(OSALASM)
+
+INCDIR = $(CHIBIOS)/os/license \
+ $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
+ $(HALINC) $(PLATFORMINC) $(BOARDINC) \
+ $(CHIBIOS)/os/various
+
+#
+# Project, sources and paths
+##############################################################################
+
+##############################################################################
+# Compiler settings
+#
+
+MCU = cortex-m0
+
+TRGT = arm-none-eabi-
+CC = $(TRGT)gcc
+CPPC = $(TRGT)g++
+# Enable loading with g++ only if you need C++ runtime support.
+# NOTE: You can use C++ even without C++ support if you are careful. C++
+# runtime support makes code size explode.
+LD = $(TRGT)gcc
+#LD = $(TRGT)g++
+CP = $(TRGT)objcopy
+AS = $(TRGT)gcc -x assembler-with-cpp
+AR = $(TRGT)ar
+OD = $(TRGT)objdump
+SZ = $(TRGT)size
+HEX = $(CP) -O ihex
+BIN = $(CP) -O binary
+SREC = $(CP) -O srec
+
+# ARM-specific options here
+AOPT =
+
+# THUMB-specific options here
+TOPT = -mthumb -DTHUMB
+
+# Define C warning options here
+CWARN = -Wall -Wextra -Wstrict-prototypes
+
+# Define C++ warning options here
+CPPWARN = -Wall -Wextra
+
+#
+# Compiler settings
+##############################################################################
+
+##############################################################################
+# Start of user section
+#
+
+# List all user C define here, like -D_DEBUG=1
+UDEFS =
+
+# Define ASM defines here
+UADEFS =
+
+# List all user directories here
+UINCDIR =
+
+# List the user directory to look for the libraries here
+ULIBDIR =
+
+# List all user libraries here
+ULIBS =
+
+#
+# End of user defines
+##############################################################################
+
+RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
+include $(RULESPATH)/rules.mk
+
+
+include $(CHIBIOS_CONTRIB)/os/various/jlink.mk
+
+
+JLINK_DEVICE = nrf51422
+JLINK_PRE_FLASH = w4 4001e504 1
+JLINK_ERASE_ALL = w4 4001e504 2\nw4 4001e50c 1\nsleep 100
+
+flash: all jlink-flash
+
diff --git a/testhal/NRF51/NRF51822/PWM/chconf.h b/testhal/NRF51/NRF51822/PWM/chconf.h
new file mode 100644
index 0000000..a753ec9
--- /dev/null
+++ b/testhal/NRF51/NRF51822/PWM/chconf.h
@@ -0,0 +1,524 @@
+/*
+ Copyright (C) 2015 Fabio Utzig
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file templates/chconf.h
+ * @brief Configuration file template.
+ * @details A copy of this file must be placed in each project directory, it
+ * contains the application specific kernel settings.
+ *
+ * @addtogroup config
+ * @details Kernel related settings and hooks.
+ * @{
+ */
+
+#ifndef _CHCONF_H_
+#define _CHCONF_H_
+
+#define _CHIBIOS_RT_CONF_
+
+/*===========================================================================*/
+/**
+ * @name System timers settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief System time counter resolution.
+ * @note Allowed values are 16 or 32 bits.
+ */
+#define CH_CFG_ST_RESOLUTION 32
+
+/**
+ * @brief System tick frequency.
+ * @details Frequency of the system timer that drives the system ticks. This
+ * setting also defines the system tick time unit.
+ */
+#define CH_CFG_ST_FREQUENCY 1000
+
+/**
+ * @brief Time delta constant for the tick-less mode.
+ * @note If this value is zero then the system uses the classic
+ * periodic tick. This value represents the minimum number
+ * of ticks that is safe to specify in a timeout directive.
+ * The value one is not valid, timeouts are rounded up to
+ * this value.
+ */
+#define CH_CFG_ST_TIMEDELTA 0
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Round robin interval.
+ * @details This constant is the number of system ticks allowed for the
+ * threads before preemption occurs. Setting this value to zero
+ * disables the preemption for threads with equal priority and the
+ * round robin becomes cooperative. Note that higher priority
+ * threads can still preempt, the kernel is always preemptive.
+ * @note Disabling the round robin preemption makes the kernel more compact
+ * and generally faster.
+ * @note The round robin preemption is not supported in tickless mode and
+ * must be set to zero in that case.
+ */
+#define CH_CFG_TIME_QUANTUM 20
+
+/**
+ * @brief Managed RAM size.
+ * @details Size of the RAM area to be managed by the OS. If set to zero
+ * then the whole available RAM is used. The core memory is made
+ * available to the heap allocator and/or can be used directly through
+ * the simplified core memory allocator.
+ *
+ * @note In order to let the OS manage the whole RAM the linker script must
+ * provide the @p __heap_base__ and @p __heap_end__ symbols.
+ * @note Requires @p CH_CFG_USE_MEMCORE.
+ */
+#define CH_CFG_MEMCORE_SIZE 0
+
+/**
+ * @brief Idle thread automatic spawn suppression.
+ * @details When this option is activated the function @p chSysInit()
+ * does not spawn the idle thread. The application @p main()
+ * function becomes the idle thread and must implement an
+ * infinite loop.
+ */
+#define CH_CFG_NO_IDLE_THREAD FALSE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Performance options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief OS optimization.
+ * @details If enabled then time efficient rather than space efficient code
+ * is used when two possible implementations exist.
+ *
+ * @note This is not related to the compiler optimization options.
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_OPTIMIZE_SPEED TRUE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Subsystem options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Time Measurement APIs.
+ * @details If enabled then the time measurement APIs are included in
+ * the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_TM FALSE
+
+/**
+ * @brief Threads registry APIs.
+ * @details If enabled then the registry APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_REGISTRY TRUE
+
+/**
+ * @brief Threads synchronization APIs.
+ * @details If enabled then the @p chThdWait() function is included in
+ * the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_WAITEXIT TRUE
+
+/**
+ * @brief Semaphores APIs.
+ * @details If enabled then the Semaphores APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_SEMAPHORES TRUE
+
+/**
+ * @brief Semaphores queuing mode.
+ * @details If enabled then the threads are enqueued on semaphores by
+ * priority rather than in FIFO order.
+ *
+ * @note The default is @p FALSE. Enable this if you have special
+ * requirements.
+ * @note Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE
+
+/**
+ * @brief Mutexes APIs.
+ * @details If enabled then the mutexes APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_MUTEXES TRUE
+
+/**
+ * @brief Enables recursive behavior on mutexes.
+ * @note Recursive mutexes are heavier and have an increased
+ * memory footprint.
+ *
+ * @note The default is @p FALSE.
+ * @note Requires @p CH_CFG_USE_MUTEXES.
+ */
+#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE
+
+/**
+ * @brief Conditional Variables APIs.
+ * @details If enabled then the conditional variables APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_MUTEXES.
+ */
+#define CH_CFG_USE_CONDVARS TRUE
+
+/**
+ * @brief Conditional Variables APIs with timeout.
+ * @details If enabled then the conditional variables APIs with timeout
+ * specification are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_CONDVARS.
+ */
+#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE
+
+/**
+ * @brief Events Flags APIs.
+ * @details If enabled then the event flags APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_EVENTS TRUE
+
+/**
+ * @brief Events Flags APIs with timeout.
+ * @details If enabled then the events APIs with timeout specification
+ * are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_EVENTS.
+ */
+#define CH_CFG_USE_EVENTS_TIMEOUT TRUE
+
+/**
+ * @brief Synchronous Messages APIs.
+ * @details If enabled then the synchronous messages APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_MESSAGES TRUE
+
+/**
+ * @brief Synchronous Messages queuing mode.
+ * @details If enabled then messages are served by priority rather than in
+ * FIFO order.
+ *
+ * @note The default is @p FALSE. Enable this if you have special
+ * requirements.
+ * @note Requires @p CH_CFG_USE_MESSAGES.
+ */
+#define CH_CFG_USE_MESSAGES_PRIORITY FALSE
+
+/**
+ * @brief Mailboxes APIs.
+ * @details If enabled then the asynchronous messages (mailboxes) APIs are
+ * included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_MAILBOXES TRUE
+
+/**
+ * @brief I/O Queues APIs.
+ * @details If enabled then the I/O queues APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_QUEUES TRUE
+
+/**
+ * @brief Core Memory Manager APIs.
+ * @details If enabled then the core memory manager APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMCORE TRUE
+
+/**
+ * @brief Heap Allocator APIs.
+ * @details If enabled then the memory heap allocator APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
+ * @p CH_CFG_USE_SEMAPHORES.
+ * @note Mutexes are recommended.
+ */
+#define CH_CFG_USE_HEAP TRUE
+
+/**
+ * @brief Memory Pools Allocator APIs.
+ * @details If enabled then the memory pools allocator APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMPOOLS TRUE
+
+/**
+ * @brief Dynamic Threads APIs.
+ * @details If enabled then the dynamic threads creation APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_WAITEXIT.
+ * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
+ */
+#define CH_CFG_USE_DYNAMIC TRUE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Debug options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Debug option, kernel statistics.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_STATISTICS FALSE
+
+/**
+ * @brief Debug option, system state check.
+ * @details If enabled the correct call protocol for system APIs is checked
+ * at runtime.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_SYSTEM_STATE_CHECK FALSE
+
+/**
+ * @brief Debug option, parameters checks.
+ * @details If enabled then the checks on the API functions input
+ * parameters are activated.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_ENABLE_CHECKS FALSE
+
+/**
+ * @brief Debug option, consistency checks.
+ * @details If enabled then all the assertions in the kernel code are
+ * activated. This includes consistency checks inside the kernel,
+ * runtime anomalies and port-defined checks.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_ENABLE_ASSERTS FALSE
+
+/**
+ * @brief Debug option, trace buffer.
+ * @details If enabled then the context switch circular trace buffer is
+ * activated.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_ENABLE_TRACE FALSE
+
+/**
+ * @brief Debug option, stack checks.
+ * @details If enabled then a runtime stack check is performed.
+ *
+ * @note The default is @p FALSE.
+ * @note The stack check is performed in a architecture/port dependent way.
+ * It may not be implemented or some ports.
+ * @note The default failure mode is to halt the system with the global
+ * @p panic_msg variable set to @p NULL.
+ */
+#define CH_DBG_ENABLE_STACK_CHECK FALSE
+
+/**
+ * @brief Debug option, stacks initialization.
+ * @details If enabled then the threads working area is filled with a byte
+ * value when a thread is created. This can be useful for the
+ * runtime measurement of the used stack.
+ *
+ * @note The default is @p FALSE.
+ */
+#define CH_DBG_FILL_THREADS FALSE
+
+/**
+ * @brief Debug option, threads profiling.
+ * @details If enabled then a field is added to the @p thread_t structure that
+ * counts the system ticks occurred while executing the thread.
+ *
+ * @note The default is @p FALSE.
+ * @note This debug option is not currently compatible with the
+ * tickless mode.
+ */
+#define CH_DBG_THREADS_PROFILING FALSE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel hooks
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Threads descriptor structure extension.
+ * @details User fields added to the end of the @p thread_t structure.
+ */
+#define CH_CFG_THREAD_EXTRA_FIELDS \
+ /* Add threads custom fields here.*/
+
+/**
+ * @brief Threads initialization hook.
+ * @details User initialization code added to the @p chThdInit() API.
+ *
+ * @note It is invoked from within @p chThdInit() and implicitly from all
+ * the threads creation APIs.
+ */
+#define CH_CFG_THREAD_INIT_HOOK(tp) { \
+ /* Add threads initialization code here.*/ \
+}
+
+/**
+ * @brief Threads finalization hook.
+ * @details User finalization code added to the @p chThdExit() API.
+ *
+ * @note It is inserted into lock zone.
+ * @note It is also invoked when the threads simply return in order to
+ * terminate.
+ */
+#define CH_CFG_THREAD_EXIT_HOOK(tp) { \
+ /* Add threads finalization code here.*/ \
+}
+
+/**
+ * @brief Context switch hook.
+ * @details This hook is invoked just before switching between threads.
+ */
+#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \
+ /* Context switch code here.*/ \
+}
+
+/**
+ * @brief ISR enter hook.
+ */
+#define CH_CFG_IRQ_PROLOGUE_HOOK() { \
+ /* IRQ prologue code here.*/ \
+}
+
+/**
+ * @brief ISR exit hook.
+ */
+#define CH_CFG_IRQ_EPILOGUE_HOOK() { \
+ /* IRQ epilogue code here.*/ \
+}
+
+/**
+ * @brief Idle thread enter hook.
+ * @note This hook is invoked within a critical zone, no OS functions
+ * should be invoked from here.
+ * @note This macro can be used to activate a power saving mode.
+ */
+#define CH_CFG_IDLE_ENTER_HOOK() { \
+}
+
+/**
+ * @brief Idle thread leave hook.
+ * @note This hook is invoked within a critical zone, no OS functions
+ * should be invoked from here.
+ * @note This macro can be used to deactivate a power saving mode.
+ */
+#define CH_CFG_IDLE_LEAVE_HOOK() { \
+}
+
+/**
+ * @brief Idle Loop hook.
+ * @details This hook is continuously invoked by the idle thread loop.
+ */
+#define CH_CFG_IDLE_LOOP_HOOK() { \
+ /* Idle loop code here.*/ \
+}
+
+/**
+ * @brief System tick event hook.
+ * @details This hook is invoked in the system tick handler immediately
+ * after processing the virtual timers queue.
+ */
+#define CH_CFG_SYSTEM_TICK_HOOK() { \
+ /* System tick event code here.*/ \
+}
+
+/**
+ * @brief System halt hook.
+ * @details This hook is invoked in case to a system halting error before
+ * the system is halted.
+ */
+#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \
+ /* System halt code here.*/ \
+}
+
+/**
+ * @brief Trace hook.
+ * @details This hook is invoked each time a new record is written in the
+ * trace buffer.
+ */
+#define CH_CFG_TRACE_HOOK(tep) { \
+ /* Trace code here.*/ \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/* Port-specific settings (override port settings defaulted in chcore.h). */
+/*===========================================================================*/
+
+#endif /* _CHCONF_H_ */
+
+/** @} */
diff --git a/testhal/NRF51/NRF51822/PWM/halconf.h b/testhal/NRF51/NRF51822/PWM/halconf.h
new file mode 100644
index 0000000..58e6a6b
--- /dev/null
+++ b/testhal/NRF51/NRF51822/PWM/halconf.h
@@ -0,0 +1,327 @@
+/*
+ Copyright (C) 2015 Fabio Utzig
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file templates/halconf.h
+ * @brief HAL configuration header.
+ * @details HAL configuration file, this file allows to enable or disable the
+ * various device drivers from your application. You may also use
+ * this file in order to override the device drivers default settings.
+ *
+ * @addtogroup HAL_CONF
+ * @{
+ */
+
+#ifndef _HALCONF_H_
+#define _HALCONF_H_
+
+#include "mcuconf.h"
+
+/**
+ * @brief Enables the PAL subsystem.
+ */
+#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
+#define HAL_USE_PAL TRUE
+#endif
+
+/**
+ * @brief Enables the ADC subsystem.
+ */
+#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
+#define HAL_USE_ADC FALSE
+#endif
+
+/**
+ * @brief Enables the CAN subsystem.
+ */
+#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
+#define HAL_USE_CAN FALSE
+#endif
+
+/**
+ * @brief Enables the EXT subsystem.
+ */
+#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
+#define HAL_USE_EXT FALSE
+#endif
+
+/**
+ * @brief Enables the GPT subsystem.
+ */
+#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
+#define HAL_USE_GPT FALSE
+#endif
+
+/**
+ * @brief Enables the I2C subsystem.
+ */
+#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
+#define HAL_USE_I2C FALSE
+#endif
+
+/**
+ * @brief Enables the I2S subsystem.
+ */
+#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
+#define HAL_USE_I2S FALSE
+#endif
+
+/**
+ * @brief Enables the ICU subsystem.
+ */
+#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
+#define HAL_USE_ICU FALSE
+#endif
+
+/**
+ * @brief Enables the MAC subsystem.
+ */
+#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
+#define HAL_USE_MAC FALSE
+#endif
+
+/**
+ * @brief Enables the MMC_SPI subsystem.
+ */
+#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_MMC_SPI FALSE
+#endif
+
+/**
+ * @brief Enables the PWM subsystem.
+ */
+#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
+#define HAL_USE_PWM TRUE
+#endif
+
+/**
+ * @brief Enables the RTC subsystem.
+ */
+#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
+#define HAL_USE_RTC FALSE
+#endif
+
+/**
+ * @brief Enables the SDC subsystem.
+ */
+#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
+#define HAL_USE_SDC FALSE
+#endif
+
+/**
+ * @brief Enables the SERIAL subsystem.
+ */
+#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL TRUE
+#endif
+
+/**
+ * @brief Enables the SERIAL over USB subsystem.
+ */
+#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL_USB FALSE
+#endif
+
+/**
+ * @brief Enables the SPI subsystem.
+ */
+#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_SPI FALSE
+#endif
+
+/**
+ * @brief Enables the UART subsystem.
+ */
+#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
+#define HAL_USE_UART FALSE
+#endif
+
+/**
+ * @brief Enables the USB subsystem.
+ */
+#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
+#define HAL_USE_USB FALSE
+#endif
+
+/*===========================================================================*/
+/* ADC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
+#define ADC_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define ADC_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/*===========================================================================*/
+/* CAN driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Sleep mode related APIs inclusion switch.
+ */
+#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
+#define CAN_USE_SLEEP_MODE TRUE
+#endif
+
+/*===========================================================================*/
+/* I2C driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the mutual exclusion APIs on the I2C bus.
+ */
+#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define I2C_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/*===========================================================================*/
+/* MAC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
+#define MAC_USE_ZERO_COPY FALSE
+#endif
+
+/**
+ * @brief Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
+#define MAC_USE_EVENTS TRUE
+#endif
+
+/*===========================================================================*/
+/* MMC_SPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ * routines releasing some extra CPU time for the threads with
+ * lower priority, this may slow down the driver a bit however.
+ * This option is recommended also if the SPI driver does not
+ * use a DMA channel and heavily loads the CPU.
+ */
+#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
+#define MMC_NICE_WAITING TRUE
+#endif
+
+/*===========================================================================*/
+/* SDC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Number of initialization attempts before rejecting the card.
+ * @note Attempts are performed at 10mS intervals.
+ */
+#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
+#define SDC_INIT_RETRY 100
+#endif
+
+/**
+ * @brief Include support for MMC cards.
+ * @note MMC support is not yet implemented so this option must be kept
+ * at @p FALSE.
+ */
+#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
+#define SDC_MMC_SUPPORT FALSE
+#endif
+
+/**
+ * @brief Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ * routines releasing some extra CPU time for the threads with
+ * lower priority, this may slow down the driver a bit however.
+ */
+#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
+#define SDC_NICE_WAITING TRUE
+#endif
+
+/*===========================================================================*/
+/* SERIAL driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Default bit rate.
+ * @details Configuration parameter, this is the baud rate selected for the
+ * default configuration.
+ */
+#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
+#define SERIAL_DEFAULT_BITRATE 38400
+#endif
+
+/**
+ * @brief Serial buffers size.
+ * @details Configuration parameter, you can change the depth of the queue
+ * buffers depending on the requirements of your application.
+ * @note The default is 64 bytes for both the transmission and receive
+ * buffers.
+ */
+#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_BUFFERS_SIZE 16
+#endif
+
+/*===========================================================================*/
+/* SERIAL_USB driver related setting. */
+/*===========================================================================*/
+
+/**
+ * @brief Serial over USB buffers size.
+ * @details Configuration parameter, the buffer size must be a multiple of
+ * the USB data endpoint maximum packet size.
+ * @note The default is 64 bytes for both the transmission and receive
+ * buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_SIZE 256
+#endif
+
+/*===========================================================================*/
+/* SPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
+#define SPI_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define SPI_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+#endif /* _HALCONF_H_ */
+
+/** @} */
diff --git a/testhal/NRF51/NRF51822/PWM/main.c b/testhal/NRF51/NRF51822/PWM/main.c
new file mode 100644
index 0000000..b93c3b2
--- /dev/null
+++ b/testhal/NRF51/NRF51822/PWM/main.c
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2016 Stéphane D'Alu
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "ch.h"
+#include "hal.h"
+
+static void pwm_cb_period(PWMDriver *pwmp) {
+ (void)pwmp;
+
+ palTogglePad(IOPORT1, LED0);
+ palClearPad(IOPORT1, LED1);
+
+}
+
+static void pwm_cb_channel0(PWMDriver *pwmp) {
+ (void)pwmp;
+ palSetPad(IOPORT1, LED1);
+}
+
+
+/*
+ * Application entry point.
+ */
+int main(void) {
+ PWMConfig pwmcfg = {
+ .frequency = PWM_FREQUENCY_31250HZ,
+ .period = 31250,
+ .callback = pwm_cb_period,
+ { {PWM_OUTPUT_ACTIVE_HIGH, pwm_cb_channel0},
+ {PWM_OUTPUT_DISABLED, NULL},
+ {PWM_OUTPUT_DISABLED, NULL}
+ },
+ };
+
+ /*
+ * System initializations.
+ * - HAL initialization, this also initializes the configured device drivers
+ * and performs the board-specific initializations.
+ * - Kernel initialization, the main() function becomes a thread and the
+ * RTOS is active.
+ */
+ halInit();
+ chSysInit();
+
+ /*
+ *
+ */
+ pwmStart(&PWMD1, &pwmcfg);
+ pwmEnablePeriodicNotification(&PWMD1);
+ pwmEnableChannel(&PWMD1, 0, PWM_FRACTION_TO_WIDTH(&PWMD1, 2, 1));
+ pwmEnableChannelNotification(&PWMD1, 0);
+
+ while (1) {
+ chThdSleepMilliseconds(500);
+ }
+}
diff --git a/testhal/NRF51/NRF51822/PWM/mcuconf.h b/testhal/NRF51/NRF51822/PWM/mcuconf.h
new file mode 100644
index 0000000..1694678
--- /dev/null
+++ b/testhal/NRF51/NRF51822/PWM/mcuconf.h
@@ -0,0 +1,29 @@
+/*
+ Copyright (C) 2015 Fabio Utzig
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef _MCUCONF_H_
+#define _MCUCONF_H_
+
+/*
+ * HAL driver system settings.
+ */
+#define NRF51_SERIAL_USE_UART0 TRUE
+#define NRF51_ST_USE_RTC0 TRUE
+#define NRF51_ST_USE_RTC1 FALSE
+#define NRF51_ST_USE_TIMER0 FALSE
+#define NRF51_PWM_USE_TIMER0 TRUE
+
+#endif /* _MCUCONF_H_ */