From b1fc6088e6cbc0485d3912c35fc9369953a41697 Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Sat, 14 Feb 2015 16:42:46 +0100 Subject: [PATCH 01/11] cpu/samd21: Initial import of UART_1 --- boards/samr21-xpro/include/periph_conf.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 0946adbbd83a..71bbef07a26d 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -14,6 +14,7 @@ * @brief Peripheral MCU configuration for the Atmel SAM R21 Xplained Pro board * * @author Thomas Eichinger + * @author Peter Kietzmann */ #ifndef __PERIPH_CONF_H @@ -49,9 +50,9 @@ extern "C" { * @name UART configuration * @{ */ -#define UART_NUMOF (1U) +#define UART_NUMOF (2U) #define UART_0_EN 1 -#define UART_1_EN 0 +#define UART_1_EN 1 #define UART_2_EN 0 #define UART_3_EN 0 #define UART_IRQ_PRIO 1 @@ -69,12 +70,15 @@ extern "C" { /* UART 1 device configuration */ -#define UART_1_DEV -#define UART_1_IRQ -#define UART_1_ISR +#define UART_1_DEV SERCOM5->USART +#define UART_1_IRQ SERCOM5_IRQn +#define UART_1_ISR isr_sercom5 /* UART 1 pin configuration */ -#define UART_1_PORT -#define UART_1_PINS +#define UART_1_PORT (PORT->Group[0]) +#define UART_1_TX_PIN (22) +#define UART_1_RX_PIN (23) +#define UART_1_PINS (PORT_PA22 | PORT_PA23) +#define UART_1_REF_F (8000000UL) /** @} */ From 4b812997f8d41ad2a6c37cc6590b6b4e6c54b55a Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Sat, 14 Feb 2015 16:47:40 +0100 Subject: [PATCH 02/11] [SQUASH ME] adapted driver implementation --- cpu/samd21/periph/uart.c | 181 ++++++++++++++++++++++++++++++--------- 1 file changed, 142 insertions(+), 39 deletions(-) diff --git a/cpu/samd21/periph/uart.c b/cpu/samd21/periph/uart.c index 8cb97a3bf6f4..853abc3f2992 100644 --- a/cpu/samd21/periph/uart.c +++ b/cpu/samd21/periph/uart.c @@ -15,6 +15,7 @@ * * @author Thomas Eichinger * @author Troels Hoffmeyer + * @author Peter Kietzmann * * @} */ @@ -70,29 +71,50 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, uart_tx_cb_t t /* configure interrupts and enable RX interrupt */ switch (uart) { +#if UART_0_EN case UART_0: NVIC_SetPriority(UART_0_IRQ, UART_IRQ_PRIO); NVIC_EnableIRQ(UART_0_IRQ); UART_0_DEV.INTENSET.bit.RXC = 1; break; +#endif +#if UART_1_EN + case UART_1: + NVIC_SetPriority(UART_1_IRQ, UART_IRQ_PRIO); + NVIC_EnableIRQ(UART_1_IRQ); + UART_1_DEV.INTENSET.bit.RXC = 1; + break; +#endif } return 0; } int uart_init_blocking(uart_t uart, uint32_t baudrate) { - /* Calculate the BAUD value */ - uint64_t temp1 = ((16 * ((uint64_t)baudrate)) << 32); - uint64_t ratio = _long_division(temp1 , UART_0_REF_F); - uint64_t scale = ((uint64_t)1 << 32) - ratio; - uint64_t baud_calculated = (65536 * scale) >> 32; + SercomUsart* uart_dev = NULL; + PortGroup* port_group = NULL; + uint32_t uart_ref_f = 0; + uint32_t tx_pin = 0; + uint32_t rx_pin = 0; + uint32_t pins = 0; + switch (uart) { #if UART_0_EN case UART_0: - /* Turn on power manager for sercom */ + port_group = &UART_0_PORT; + uart_dev = &UART_0_DEV; + uart_ref_f = UART_0_REF_F; + tx_pin = UART_0_TX_PIN; + rx_pin = UART_0_RX_PIN; + pins = UART_0_PINS; + + /* Turn on power manager for sercom0 */ PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0; + /* Enable generic clock generator0 */ + GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | (GCLK_CLKCTRL_ID(GCLK_CLKCTRL_GEN_GCLK0_Val))); + /* configure GCLK0 to feed sercom0 */; GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (SERCOM0_GCLK_ID_CORE << GCLK_CLKCTRL_ID_Pos))); while (GCLK->STATUS.bit.SYNCBUSY); @@ -100,41 +122,84 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (SERCOM0_GCLK_ID_SLOW << GCLK_CLKCTRL_ID_Pos))); while (GCLK->STATUS.bit.SYNCBUSY); - /* configure PINS to input/output*/ - UART_0_PORT.DIRSET.reg = (1 << UART_0_TX_PIN); /* tx's direction is output */ - UART_0_PORT.PINCFG[UART_0_RX_PIN % 32].bit.INEN = true; /* buffer rx pin's value */ - - /* enable PMUX for pins and set to config D. See spec p. 12 */ - UART_0_PORT.WRCONFIG.reg = PORT_WRCONFIG_WRPINCFG \ - | PORT_WRCONFIG_WRPMUX \ - | PORT_WRCONFIG_PMUX(0x3) \ - | PORT_WRCONFIG_PMUXEN \ - | UART_0_PINS; - - UART_0_DEV.CTRLA.bit.ENABLE = 0; //Disable to write, need to sync tho - while(UART_0_DEV.SYNCBUSY.bit.ENABLE); - - /* set to LSB, asynchronous mode without parity, PAD0 Tx, PAD1 Rx, - * 16x over-sampling, internal clk */ - UART_0_DEV.CTRLA.reg = SERCOM_USART_CTRLA_DORD \ - | SERCOM_USART_CTRLA_FORM(0x0) \ - | SERCOM_USART_CTRLA_SAMPA(0x0) \ - | SERCOM_USART_CTRLA_TXPO(0x0) \ - | SERCOM_USART_CTRLA_RXPO(0x1) \ - | SERCOM_USART_CTRLA_SAMPR(0x0) \ - | SERCOM_USART_CTRLA_MODE_USART_INT_CLK; - - /* Set baud rate */ - UART_0_DEV.BAUD.bit.BAUD = baud_calculated; - - /* enable receiver and transmitter, one stop bit*/ - UART_0_DEV.CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN); - while(UART_0_DEV.SYNCBUSY.bit.CTRLB); + break; +#endif +#if UART_1_EN + case UART_1: + port_group = &UART_1_PORT; + uart_dev = &UART_1_DEV; + uart_ref_f = UART_1_REF_F; + tx_pin = UART_1_TX_PIN; + rx_pin = UART_1_RX_PIN; + pins = UART_1_PINS; + + /* Turn on power manager for sercom5 */ + PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5; + + /* Enable generic clock generator1 */ + GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | (GCLK_CLKCTRL_ID(GCLK_CLKCTRL_GEN_GCLK1_Val))); + + /* configure GCLK1 to feed sercom5 */; + GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | (SERCOM5_GCLK_ID_CORE << GCLK_CLKCTRL_ID_Pos))); + while (GCLK->STATUS.bit.SYNCBUSY); + + GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | (SERCOM5_GCLK_ID_SLOW << GCLK_CLKCTRL_ID_Pos))); + while (GCLK->STATUS.bit.SYNCBUSY); break; #endif + default: + return -2; + } + + if (port_group == NULL) { + return -2; } + /* configure PINS to input/output*/ + port_group->DIRSET.reg = (1 << tx_pin); /* tx's direction is output */ + + port_group->PINCFG[rx_pin % 32].bit.DRVSTR = 0; /* pin drive strength is set to normal */ + port_group->PINCFG[tx_pin % 32].bit.DRVSTR = 0; + port_group->PINCFG[rx_pin % 32].bit.INEN = 1; /* buffer rx pin's value */ + port_group->PINCFG[rx_pin % 32].bit.PMUXEN = 1; /* enables peripheral multiplexer */ + port_group->PINCFG[tx_pin % 32].bit.PMUXEN = 1; /* enables peripheral multiplexer */ + + + /* enable PMUX for pins and set to config D. See spec p. 12 */ + port_group->WRCONFIG.reg = PORT_WRCONFIG_WRPINCFG /* PINCFGy registers of the selected pins will be updated */ + | PORT_WRCONFIG_WRPMUX /* PMUXn registers of the selected pins will be updated */ + | PORT_WRCONFIG_PMUX(0x3) /* Multiplexer peripheral function D */ + | PORT_WRCONFIG_PMUXEN /* Peripheral multiplexer enable */ + | pins; /* Pinmask */ + + uart_dev->CTRLA.bit.ENABLE = 0; /* Disable to write, need to sync to */ + while(uart_dev->SYNCBUSY.bit.ENABLE); + + /* set to LSB, asynchronous mode without parity, PAD0 Tx, PAD1 Rx, + * 16x over-sampling, internal clk */ + uart_dev->CTRLA.reg = SERCOM_USART_CTRLA_DORD /* LSB first */ + | SERCOM_USART_CTRLA_FORM(0x0) /* USART frame */ + | SERCOM_USART_CTRLA_SAMPA(0x0) /* 16x Oversampling */ + | SERCOM_USART_CTRLA_TXPO(0x0) /* PAD[0] */ + | SERCOM_USART_CTRLA_RXPO(0x1) /* PAD[1] */ + | SERCOM_USART_CTRLA_SAMPR(0x0) /* 16x Oversampling */ + | SERCOM_USART_CTRLA_MODE_USART_INT_CLK; /* USART with internal clock */ + + + /* Calculate the BAUD value */ + uint64_t temp1 = ((16 * ((uint64_t)baudrate)) << 32); + uint64_t ratio = _long_division(temp1 , uart_ref_f); + uint64_t scale = ((uint64_t)1 << 32) - ratio; + uint64_t baud_calculated = (65536 * scale) >> 32; + + /* Set baud rate */ + uart_dev->BAUD.bit.BAUD = baud_calculated; + + /* enable receiver and transmitter, one stop bit*/ + uart_dev->CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN); + while(uart_dev->SYNCBUSY.bit.CTRLB); + uart_poweron(uart); return 0; } @@ -152,9 +217,16 @@ void uart_tx_end(uart_t uart) int uart_write(uart_t uart, char data) { switch (uart) { +#if UART_0_EN case UART_0: UART_0_DEV.DATA.reg = (uint8_t)data; break; +#endif +#if UART_1_EN + case UART_1: + UART_1_DEV.DATA.reg = (uint8_t)data; + break; +#endif } return 1; } @@ -162,10 +234,18 @@ int uart_write(uart_t uart, char data) int uart_read_blocking(uart_t uart, char *data) { switch (uart) { +#if UART_0_EN case UART_0: while (UART_0_DEV.INTFLAG.bit.RXC == 0); *data = (char)(0x00ff & UART_0_DEV.DATA.reg); break; +#endif +#if UART_1_EN + case UART_1: + while (UART_1_DEV.INTFLAG.bit.RXC == 0); + *data = (char)(0x00ff & UART_1_DEV.DATA.reg); + break; +#endif } return 1; } @@ -173,24 +253,44 @@ int uart_read_blocking(uart_t uart, char *data) int uart_write_blocking(uart_t uart, char data) { switch (uart) { +#if UART_0_EN case UART_0: while (UART_0_DEV.INTFLAG.bit.DRE == 0); UART_0_DEV.DATA.reg = (uint8_t)data; break; +#endif +#if UART_1_EN + case UART_1: + while (UART_1_DEV.INTFLAG.bit.DRE == 0); + UART_1_DEV.DATA.reg = (uint8_t)data; + break; +#endif } return 1; } void uart_poweron(uart_t uart) { +#if UART_0_EN while (UART_0_DEV.SYNCBUSY.reg); UART_0_DEV.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; +#endif +#if UART_1_EN + while (UART_1_DEV.SYNCBUSY.reg); + UART_1_DEV.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; +#endif } void uart_poweroff(uart_t uart) { +#if UART_0_EN while (UART_0_DEV.SYNCBUSY.reg); UART_0_DEV.CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; +#endif +#if UART_1_EN + while (UART_1_DEV.SYNCBUSY.reg); + UART_1_DEV.CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; +#endif } #if UART_0_EN @@ -199,6 +299,12 @@ void UART_0_ISR(void) irq_handler(UART_0, &UART_0_DEV); } #endif +#if UART_1_EN +void UART_1_ISR(void) +{ + irq_handler(UART_1, &UART_1_DEV); +} +#endif static inline void irq_handler(uint8_t uartnum, SercomUsart *dev) { @@ -226,9 +332,6 @@ static inline void irq_handler(uint8_t uartnum, SercomUsart *dev) } } - - - static uint64_t _long_division(uint64_t n, uint64_t d) { int32_t i; From 0c6b88f0a5917d0c7ba97241819d554bdfa20213 Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 16 Feb 2015 10:16:42 +0100 Subject: [PATCH 03/11] [SQUASH ME] addressed @thomaseichingers comments (GCLK1->GCLK0) --- cpu/samd21/periph/uart.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/cpu/samd21/periph/uart.c b/cpu/samd21/periph/uart.c index 853abc3f2992..c10f0ead611d 100644 --- a/cpu/samd21/periph/uart.c +++ b/cpu/samd21/periph/uart.c @@ -112,9 +112,6 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) /* Turn on power manager for sercom0 */ PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0; - /* Enable generic clock generator0 */ - GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | (GCLK_CLKCTRL_ID(GCLK_CLKCTRL_GEN_GCLK0_Val))); - /* configure GCLK0 to feed sercom0 */; GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (SERCOM0_GCLK_ID_CORE << GCLK_CLKCTRL_ID_Pos))); while (GCLK->STATUS.bit.SYNCBUSY); @@ -136,14 +133,11 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) /* Turn on power manager for sercom5 */ PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5; - /* Enable generic clock generator1 */ - GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | (GCLK_CLKCTRL_ID(GCLK_CLKCTRL_GEN_GCLK1_Val))); - - /* configure GCLK1 to feed sercom5 */; - GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | (SERCOM5_GCLK_ID_CORE << GCLK_CLKCTRL_ID_Pos))); + /* configure GCLK0 to feed sercom5 */; + GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (SERCOM5_GCLK_ID_CORE << GCLK_CLKCTRL_ID_Pos))); while (GCLK->STATUS.bit.SYNCBUSY); - GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | (SERCOM5_GCLK_ID_SLOW << GCLK_CLKCTRL_ID_Pos))); + GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (SERCOM5_GCLK_ID_SLOW << GCLK_CLKCTRL_ID_Pos))); while (GCLK->STATUS.bit.SYNCBUSY); break; From 06803b58db2ef18cee9896bdd01faa7c0031ec87 Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 16 Feb 2015 11:16:10 +0100 Subject: [PATCH 04/11] [SQUASH ME] changed port to UART_1 --- tests/periph_uart_int/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/periph_uart_int/main.c b/tests/periph_uart_int/main.c index 8e5015705b4d..05c63768fc10 100644 --- a/tests/periph_uart_int/main.c +++ b/tests/periph_uart_int/main.c @@ -42,7 +42,7 @@ /* only build this test if the UART driver is supported */ #if UART_NUMOF -#define DEV UART_0 +#define DEV UART_1 #define BAUD 115200 static volatile int main_pid; From 9c8579921eda9818e0fd2b0110047b5373a763f8 Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 16 Feb 2015 11:16:43 +0100 Subject: [PATCH 05/11] [SQUASH ME] set HWSEL for possible upper PORT group pin cinfigs. --- cpu/samd21/periph/uart.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpu/samd21/periph/uart.c b/cpu/samd21/periph/uart.c index c10f0ead611d..8808f2d565c4 100644 --- a/cpu/samd21/periph/uart.c +++ b/cpu/samd21/periph/uart.c @@ -97,6 +97,7 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) uint32_t tx_pin = 0; uint32_t rx_pin = 0; uint32_t pins = 0; + uint32_t HWSEL = 0; switch (uart) { @@ -108,6 +109,7 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) tx_pin = UART_0_TX_PIN; rx_pin = UART_0_RX_PIN; pins = UART_0_PINS; + HWSEL = 0; /* Turn on power manager for sercom0 */ PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0; @@ -129,6 +131,7 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) tx_pin = UART_1_TX_PIN; rx_pin = UART_1_RX_PIN; pins = UART_1_PINS; + HWSEL = (PORT_WRCONFIG_HWSEL); /* Turn on power manager for sercom5 */ PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5; @@ -161,7 +164,8 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) /* enable PMUX for pins and set to config D. See spec p. 12 */ - port_group->WRCONFIG.reg = PORT_WRCONFIG_WRPINCFG /* PINCFGy registers of the selected pins will be updated */ + port_group->WRCONFIG.reg = HWSEL /* Upper/lower 16 pins of PORT will be configured */ + | PORT_WRCONFIG_WRPINCFG /* PINCFGy registers of the selected pins will be updated */ | PORT_WRCONFIG_WRPMUX /* PMUXn registers of the selected pins will be updated */ | PORT_WRCONFIG_PMUX(0x3) /* Multiplexer peripheral function D */ | PORT_WRCONFIG_PMUXEN /* Peripheral multiplexer enable */ From e719eb74dcfed9d0e035a112469408d7373cbb8b Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 16 Feb 2015 12:01:40 +0100 Subject: [PATCH 06/11] [SQUASH ME] changed pinmask to %16 arithmetic in WRCONFIG register --- cpu/samd21/periph/uart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpu/samd21/periph/uart.c b/cpu/samd21/periph/uart.c index 8808f2d565c4..8e0c74abd135 100644 --- a/cpu/samd21/periph/uart.c +++ b/cpu/samd21/periph/uart.c @@ -96,7 +96,6 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) uint32_t uart_ref_f = 0; uint32_t tx_pin = 0; uint32_t rx_pin = 0; - uint32_t pins = 0; uint32_t HWSEL = 0; @@ -108,7 +107,6 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) uart_ref_f = UART_0_REF_F; tx_pin = UART_0_TX_PIN; rx_pin = UART_0_RX_PIN; - pins = UART_0_PINS; HWSEL = 0; /* Turn on power manager for sercom0 */ @@ -130,7 +128,6 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) uart_ref_f = UART_1_REF_F; tx_pin = UART_1_TX_PIN; rx_pin = UART_1_RX_PIN; - pins = UART_1_PINS; HWSEL = (PORT_WRCONFIG_HWSEL); /* Turn on power manager for sercom5 */ @@ -169,7 +166,8 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate) | PORT_WRCONFIG_WRPMUX /* PMUXn registers of the selected pins will be updated */ | PORT_WRCONFIG_PMUX(0x3) /* Multiplexer peripheral function D */ | PORT_WRCONFIG_PMUXEN /* Peripheral multiplexer enable */ - | pins; /* Pinmask */ + | (1 << ( tx_pin % 16 )) /* Pinmask */ + | (1 << ( rx_pin % 16 )); /* Pinmask */ uart_dev->CTRLA.bit.ENABLE = 0; /* Disable to write, need to sync to */ while(uart_dev->SYNCBUSY.bit.ENABLE); From a1920cb66c508a8ceeae3326ceb55995326ca718 Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 23 Feb 2015 10:47:02 +0100 Subject: [PATCH 07/11] use UART_1 for stdout --- boards/samr21-xpro/include/board.h | 2 +- cpu/samd21/syscalls.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/samr21-xpro/include/board.h b/boards/samr21-xpro/include/board.h index 7f2c838000ed..877070d099f7 100644 --- a/boards/samr21-xpro/include/board.h +++ b/boards/samr21-xpro/include/board.h @@ -53,7 +53,7 @@ extern "C" { * @name Define UART device and baudrate for stdio * @{ */ -#define STDIO UART_0 +#define STDIO UART_1 #define STDIO_BAUDRATE (115200U) #define STDIO_BUFSIZE (64U) /** @} */ diff --git a/cpu/samd21/syscalls.c b/cpu/samd21/syscalls.c index e0cc45d3e2d6..3fda428749cd 100644 --- a/cpu/samd21/syscalls.c +++ b/cpu/samd21/syscalls.c @@ -229,7 +229,7 @@ int _write_r(struct _reent *r, int fd, const void *data, unsigned int count) { char *c = (char*)data; for (int i = 0; i < count; i++) { - uart_write_blocking(UART_0, c[i]); + uart_write_blocking(STDIO, c[i]); } return count; } From 9fcff14a067f7b62d42ff816cc1195b49da7f474 Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 23 Feb 2015 11:02:41 +0100 Subject: [PATCH 08/11] import adc things --- boards/samr21-xpro/Makefile.features | 2 +- boards/samr21-xpro/include/periph_conf.h | 95 ++++++ cpu/samd21/periph/adc.c | 366 +++++++++++++++++++++++ 3 files changed, 462 insertions(+), 1 deletion(-) create mode 100644 cpu/samd21/periph/adc.c diff --git a/boards/samr21-xpro/Makefile.features b/boards/samr21-xpro/Makefile.features index 3266fbb712f2..7f9faa71dd6f 100644 --- a/boards/samr21-xpro/Makefile.features +++ b/boards/samr21-xpro/Makefile.features @@ -1,2 +1,2 @@ -FEATURES_PROVIDED += transceiver periph_gpio periph_spi cpp periph_timer periph_uart periph_i2c cpp periph_rtc periph_cpuid +FEATURES_PROVIDED += transceiver periph_gpio periph_spi cpp periph_timer periph_uart periph_i2c cpp periph_rtc periph_cpuid periph_adc FEATURES_MCU_GROUP = cortex_m0 diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 71bbef07a26d..bf1ec3c2f8db 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -249,6 +249,101 @@ extern "C" { #define GPIO_15_EXTINT /** @} */ +/** + * @ ADC Configuration + * @{ + */ +#define ADC_NUMOF (1U) +#define ADC_0_EN 1 +#define ADC_MAX_CHANNELS 8 + +/* ADC 0 device configuration */ +#define ADC_0_DEV ADC +#define ADC_0_PORT (PORT->Group[0]) +#define ADC_0_IRQ ADC_IRQn +#define ADC_0_CHANNELS 8 +/* ADC 0 Default values */ +#define ADC_0_CLK_SOURCE 0 /* GCLK_GENERATOR_0 */ +#define ADC_0_PRESCALER ADC_CTRLB_PRESCALER_DIV4 +#define ADC_0_WINDOW_MODE ADC_WINCTRL_WINMODE_DISABLE +#define ADC_0_WINDOW_LOWER 0 +#define ADC_0_WINDOW_HIGHER 0 + +#define SAMPLE_0_V_OFFSET 90 +#define SAMPLE_REF_V 2355 //2048 -> 1; 4095/3620 -> 2355 +#define ADC_0_CORRECTION_EN 1 /* enabled */ +#define ADC_0_OFFSET_CORRECTION ADC_OFFSETCORR_OFFSETCORR(SAMPLE_0_V_OFFSET) /* refert to datasheet p.811 for calculation */ +#define ADC_0_GAIN_CORRECTION ADC_GAINCORR_GAINCORR(SAMPLE_REF_V) +#define ADC_0_SAMPLE_LENGTH 0 /* disabled */ +#define ADC_0_PIN_SCAN_OFFSET_START 0 /* disabled */ +#define ADC_0_PIN_SCAN_INPUT_TO_SCAN 0 /* disabled */ +#define ADC_0_LEFT_ADJUST 0 /* disabled */ +#define ADC_0_DIFFERENTIAL_MODE 0 /* disabled */ +#define ADC_0_FREE_RUNNING 0 /* disabled */ +#define ADC_0_EVENT_ACTION 0 /* disabled */ +#define ADC_0_RUN_IN_STANDBY 0 /* disabled */ + +/* ADC 0 Module Status flags */ +#define ADC_0_STATUS_RESULT_READY (1UL << 0) +#define ADC_0_STATUS_WINDOW (1UL << 1) +#define ADC_0_STATUS_OVERRUN (1UL << 2) + +/* ADC 0 Positive Input Pins */ +#define ADC_0_POS_INPUT ADC_INPUTCTRL_MUXPOS_PIN6 + +/* ADC 0 Negative Input Pins */ +#define ADC_0_NEG_INPUT ADC_INPUTCTRL_MUXNEG_GND + +/* ADC 0 Gain Factor */ +#define ADC_0_GAIN_FACTOR_1X ADC_INPUTCTRL_GAIN_1X +#define ADC_0_GAIN_FACTOR_2X ADC_INPUTCTRL_GAIN_2X +#define ADC_0_GAIN_FACTOR_4X ADC_INPUTCTRL_GAIN_4X +#define ADC_0_GAIN_FACTOR_8X ADC_INPUTCTRL_GAIN_8X +#define ADC_0_GAIN_FACTOR_16X ADC_INPUTCTRL_GAIN_16X +/* Use this to define the value used */ +#define ADC_0_GAIN_FACTOR_DEFAULT ADC_0_GAIN_FACTOR_1X + +/* ADC 0 Resolutions */ +#define ADC_0_RES_8BIT ADC_CTRLB_RESSEL_8BIT +#define ADC_0_RES_10BIT ADC_CTRLB_RESSEL_10BIT +#define ADC_0_RES_12BIT ADC_CTRLB_RESSEL_12BIT +#define ADC_0_RES_16BIT ADC_CTRLB_RESSEL_16BIT + +/* ADC 0 Voltage reference */ +#define ADC_0_REF_INT_1V ADC_REFCTRL_REFSEL_INT1V +#define ADC_0_REF_EXT_B ADC_REFCTRL_REFSEL_AREFB +#define ADC_0_REF_COM_EN 1 +/* Use this to define the value used */ +#define ADC_0_REF_DEFAULT ADC_0_REF_EXT_B + +/* ADC 0 ACCUMULATE */ +#define ADC_0_ACCUM_DISABLE ADC_AVGCTRL_SAMPLENUM_1 +#define ADC_0_ACCUM_2 ADC_AVGCTRL_SAMPLENUM_2 +#define ADC_0_ACCUM_4 ADC_AVGCTRL_SAMPLENUM_4 +#define ADC_0_ACCUM_8 ADC_AVGCTRL_SAMPLENUM_8 +#define ADC_0_ACCUM_16 ADC_AVGCTRL_SAMPLENUM_16 +#define ADC_0_ACCUM_32 ADC_AVGCTRL_SAMPLENUM_32 +#define ADC_0_ACCUM_64 ADC_AVGCTRL_SAMPLENUM_64 +#define ADC_0_ACCUM_128 ADC_AVGCTRL_SAMPLENUM_128 +#define ADC_0_ACCUM_256 ADC_AVGCTRL_SAMPLENUM_256 +#define ADC_0_ACCUM_512 ADC_AVGCTRL_SAMPLENUM_512 +#define ADC_0_ACCUM_1024 ADC_AVGCTRL_SAMPLENUM_1024 +/* Use this to define the value used */ +#define ADC_0_ACCUM_DEFAULT ADC_0_ACCUM_DISABLE + +/* ADC 0 DEVIDE RESULT */ +#define ADC_0_DIV_RES_DISABLE 0 +#define ADC_0_DIV_RES_2 1 +#define ADC_0_DIV_RES_4 2 +#define ADC_0_DIV_RES_8 3 +#define ADC_0_DIV_RES_16 4 +#define ADC_0_DIV_RES_32 5 +#define ADC_0_DIV_RES_64 6 +#define ADC_0_DIV_RES_128 7 +/* Use this to define the value used */ +#define ADC_0_DIV_RES_DEFAULT ADC_0_DIV_RES_DISABLE +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/samd21/periph/adc.c b/cpu/samd21/periph/adc.c new file mode 100644 index 000000000000..779d152d24fa --- /dev/null +++ b/cpu/samd21/periph/adc.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup cpu_samr21 + * @{ + * + * @file + * @brief ADC driver implementation + * + * @author Rane Balslev (SAMR21) + * @author Peter Kietzmann + * + * @} + */ + +#include +#include "cpu.h" +#include "periph/adc.h" +#include "periph_conf.h" +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* guard in case that no ADC device is defined */ +#if ADC_NUMOF + +/* Prototypes */ +bool adc_syncing(Adc*); +void adc_clear_status(Adc*, uint32_t); +uint32_t adc_get_status(Adc*); +int adc_configure_with_resolution(Adc*, uint32_t); + +int adc_init(adc_t dev, adc_precision_t precision) +{ + //adc_poweron(dev); + Adc *adc = 0; + int init = 0; + switch (dev) { + #if ADC_0_EN + case ADC_0: + adc = ADC_0_DEV; + while(adc_syncing(adc)); + /*Disable adc before init*/ + adc->CTRLA.reg &= ~ADC_CTRLA_ENABLE; + switch (precision) + { + case ADC_RES_8BIT: + init = adc_configure_with_resolution(adc, ADC_0_RES_8BIT); + break; + case ADC_RES_10BIT: + init = adc_configure_with_resolution(adc, ADC_0_RES_10BIT); + break; + case ADC_RES_12BIT: + init = adc_configure_with_resolution(adc, ADC_0_RES_12BIT); + break; + case ADC_RES_16BIT: + init = adc_configure_with_resolution(adc, ADC_0_RES_16BIT); + DEBUG("Init switch DONE\n"); + break; + default: + return -1; + } + while(adc_syncing(adc)); + if(init == -1) + return -1; + /* Enable bandgap if internal ref 1 volt */ + if(ADC_0_REF_DEFAULT == ADC_0_REF_INT_1V) + { + SYSCTRL->VREF.reg |= SYSCTRL_VREF_BGOUTEN; + } + /* Enable */ + adc->CTRLA.reg |= ADC_CTRLA_ENABLE; + break; + #endif + default: + return -1; + } + return 0; +} + +int adc_sample(adc_t dev, int channel) +{ + int result = 0; + Adc *adc = 0; + switch (dev) + { + #if ADC_0_EN + case ADC_0: + adc = ADC_0_DEV; + /* Starts the ADC conversion */ + while(adc_syncing(adc)); + adc->SWTRIG.reg |= ADC_SWTRIG_START; + break; + #endif + default: + DEBUG("case default\n"); + return -1; + } + /* MUST NOT BLOCK */ + while(!(adc_get_status(adc) & ADC_0_STATUS_RESULT_READY)) + { + DEBUG("STATUS NOT READY\n"); + } + while(adc_syncing(adc)); + result = adc->RESULT.reg; + /*CLEAR RESET FLAG */ + adc_clear_status(adc, ADC_0_STATUS_RESULT_READY); + if (adc_get_status(adc) & ADC_0_STATUS_OVERRUN) + { + adc_clear_status(adc, ADC_0_STATUS_OVERRUN); + DEBUG("OVERRUN\n"); + return -1; + } + return result; +} + +void adc_poweron(adc_t dev) +{ + switch (dev) + { + #if ADC_0_EN + case ADC_0: + /* Setup generic clock mask for adc */ + PM->APBCMASK.reg |= PM_APBCMASK_ADC; + break; + #endif + default: + break; + } +} + +void adc_poweroff(adc_t dev) +{ + Adc *adc = 0; + + switch (dev) + { + #if ADC_0_EN + case ADC_0: + adc = ADC_0_DEV; + while(adc_syncing(adc)); + /* Disable */ + adc->CTRLA.reg &= ~ADC_CTRLA_ENABLE; + break; + #endif + default: + break; + } +} + +int adc_map(adc_t dev, int value, int min, int max) +{ + DEBUG("adc_map Not implemented!\n"); + return 0; +} + +float adc_mapf(adc_t dev, int value, float min, float max) +{ + DEBUG("adc_mapf Not implemented!\n"); + return 0.0; +} + +bool adc_syncing(Adc* adc) +{ + if(adc->STATUS.reg & ADC_STATUS_SYNCBUSY){ + return true; + } + return false; +} + +/* Configure ADC with defined Resolution */ +int adc_configure_with_resolution(Adc* adc, uint32_t precision) +{ + adc_poweron(ADC_0); + uint8_t divideResult = ADC_0_DIV_RES_DEFAULT; + uint32_t resolution = ADC_0_RES_16BIT; + uint32_t accumulate = ADC_0_ACCUM_DEFAULT; + if(adc->CTRLA.reg & ADC_CTRLA_SWRST) + return -1; + if(adc->CTRLA.reg & ADC_CTRLA_ENABLE) + return -1; + + /* GCLK Setup*/ + GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN + | GCLK_CLKCTRL_GEN_GCLK0 + | (ADC_GCLK_ID << GCLK_CLKCTRL_ID_Pos))); + + /* Pin Muxing */ + ADC_0_PORT.PINCFG[ ADC_0_POS_INPUT ].bit.PMUXEN = 1; + ADC_0_PORT.PMUX[ ADC_0_POS_INPUT / 2].bit.PMUXE = 1; + + /* ADC_0_POS_INPUT Input */ + ADC_0_PORT.DIRCLR.reg = (1 << ADC_INPUTCTRL_MUXPOS_PIN6_Val); + ADC_0_PORT.PINCFG[ADC_0_POS_INPUT].bit.INEN = true; + ADC_0_PORT.PINCFG[ADC_0_POS_INPUT].bit.PULLEN = false; + + if(ADC_0_NEG_INPUT != ADC_INPUTCTRL_MUXNEG_GND) + { + ADC_0_PORT.DIRCLR.reg = (1 << ADC_INPUTCTRL_MUXNEG_GND_Val); + ADC_0_PORT.PINCFG[ADC_0_NEG_INPUT].bit.INEN = true; + ADC_0_PORT.PINCFG[ADC_0_NEG_INPUT].bit.PULLEN = false; + } + + /* Set RUN_IN_STANDBY */ + adc->CTRLA.reg = (ADC_0_RUN_IN_STANDBY << ADC_CTRLA_RUNSTDBY_Pos); + + /* Set Voltage Reference */ + adc->REFCTRL.reg = (ADC_0_REF_COM_EN << ADC_REFCTRL_REFCOMP_Pos) | ADC_0_REF_DEFAULT; + + int test = adc->REFCTRL.reg; + printf("\nREFCTRL %i\n", test); + + switch (precision) + { + case ADC_0_RES_8BIT: + resolution = ADC_0_RES_8BIT; + break; + case ADC_0_RES_10BIT: + resolution = ADC_0_RES_10BIT; + break; + case ADC_0_RES_12BIT: + resolution = ADC_0_RES_12BIT; + break; + case ADC_0_RES_16BIT: + divideResult = ADC_0_DIV_RES_DISABLE; + switch(ADC_0_ACCUM_DEFAULT) + { + case ADC_0_ACCUM_512: + accumulate = ADC_0_ACCUM_512; + break; + case ADC_0_ACCUM_1024: + accumulate = ADC_0_ACCUM_1024; + break; + default: + accumulate = ADC_0_ACCUM_256; + break; + } + resolution = ADC_0_RES_16BIT; + break; + default: + DEBUG("Invalid precision"); + return -1; + } + + /* Set the accumlation and devide result */ + adc->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(divideResult) | accumulate; + + /* Set Sample length */ + adc->SAMPCTRL.reg = (ADC_0_SAMPLE_LENGTH << ADC_SAMPCTRL_SAMPLEN_Pos); + while(adc_syncing(adc)); + + /* If external vref. Pin setup */ + if(ADC_0_REF_DEFAULT == ADC_0_REF_EXT_B) + { + ADC_0_PORT.DIRCLR.reg = (1 << ADC_REFCTRL_REFSEL_AREFB_Val); + ADC_0_PORT.PINCFG[ADC_0_REF_DEFAULT].bit.INEN = true; + ADC_0_PORT.PINCFG[ADC_0_REF_DEFAULT].bit.PMUXEN = 1; + ADC_0_PORT.PINCFG[ADC_0_REF_DEFAULT].bit.PULLEN = false; + } + + /* Configure CTRLB Register HERE IS THE RESOLUTION SET!*/ + adc->CTRLB.reg = + ADC_0_PRESCALER | + resolution | + (ADC_0_CORRECTION_EN << ADC_CTRLB_CORREN_Pos) | + (ADC_0_FREE_RUNNING << ADC_CTRLB_FREERUN_Pos) | + (ADC_0_LEFT_ADJUST << ADC_CTRLB_LEFTADJ_Pos) | + (ADC_0_DIFFERENTIAL_MODE << ADC_CTRLB_DIFFMODE_Pos); + + + /* Configure Window Mode Register */ + /*adc->WINCTRL.reg = ADC_0_WINDOW_MODE; + while(adc_syncing(adc));*/ + + /* Configure lower threshold */ + adc->WINLT.reg = ADC_0_WINDOW_LOWER << ADC_WINLT_WINLT_Pos; + while(adc_syncing(adc)); + + /* Configure lower threshold */ + adc->WINUT.reg = ADC_0_WINDOW_HIGHER << ADC_WINUT_WINUT_Pos; + while(adc_syncing(adc)); + + /* Configure PIN SCAN MODE & positive & Negative Input Pins */ + adc->INPUTCTRL.reg = + ADC_0_GAIN_FACTOR_DEFAULT | + (ADC_0_PIN_SCAN_OFFSET_START << ADC_INPUTCTRL_INPUTOFFSET_Pos) | + (ADC_0_PIN_SCAN_INPUT_TO_SCAN << ADC_INPUTCTRL_INPUTSCAN_Pos) | + ADC_0_NEG_INPUT | + ADC_0_POS_INPUT; + + /* Configure event action */ + adc->EVCTRL.reg = ADC_0_EVENT_ACTION; + + if (ADC_0_CORRECTION_EN) + { + if (ADC_0_GAIN_CORRECTION > ADC_GAINCORR_GAINCORR_Msk) + { + DEBUG("Invalid gain correction\n"); + return -1; + } + else + { + /* Set gain correction value */ + adc->GAINCORR.reg = (ADC_0_GAIN_CORRECTION << ADC_GAINCORR_GAINCORR_Pos); + } + if ((int)ADC_0_OFFSET_CORRECTION > 2047 || (int)ADC_0_OFFSET_CORRECTION < -2048) + { + DEBUG("Invalid offset correction is: %i\n", ADC_0_OFFSET_CORRECTION); + return -1; + } + else + { + /* Set offset correction value */ + adc->OFFSETCORR.reg = (ADC_0_OFFSET_CORRECTION << ADC_OFFSETCORR_OFFSETCORR_Pos); + } + } + + /* Disable all interrupts */ + adc->INTENCLR.reg = + (1 << ADC_INTENCLR_SYNCRDY_Pos) | (1 << ADC_INTENCLR_WINMON_Pos) | + (1 << ADC_INTENCLR_OVERRUN_Pos) | (1 << ADC_INTENCLR_RESRDY_Pos); + + /* Load the fixed device calibration constants*/ + adc->CALIB.reg = ADC_CALIB_BIAS_CAL((*(uint32_t*)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos)) + | + ADC_CALIB_LINEARITY_CAL((*(uint64_t*)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos)); + + return 1; +} + +/* Clear interrupt status flags */ +void adc_clear_status(Adc* adc, uint32_t status_flag) +{ + uint32_t interrupt_flags = 0; + + if(status_flag & ADC_0_STATUS_RESULT_READY) + interrupt_flags |= ADC_INTFLAG_RESRDY; + if(status_flag & ADC_0_STATUS_WINDOW) + interrupt_flags |= ADC_INTFLAG_WINMON; + if(status_flag & ADC_0_STATUS_OVERRUN) + interrupt_flags |= ADC_INTFLAG_OVERRUN; + /* Clear interrupt flag*/ + adc->INTFLAG.reg = interrupt_flags; +} + +/* Get ADC status */ +uint32_t adc_get_status(Adc* adc) +{ + uint32_t interrupt_flags = adc->INTFLAG.reg; + uint32_t status_flags = 0; + + if(interrupt_flags & ADC_INTFLAG_RESRDY) + status_flags |= ADC_0_STATUS_RESULT_READY; + if(interrupt_flags & ADC_INTFLAG_WINMON) + status_flags |= ADC_0_STATUS_WINDOW; + if(interrupt_flags & ADC_INTFLAG_OVERRUN) + status_flags |= ADC_0_STATUS_OVERRUN; + return status_flags; +} + +#endif /* ADC_NUMOF */ From 03f340f5b051bec4f45cfe382f8a2b8ba34f4427 Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 23 Feb 2015 11:18:21 +0100 Subject: [PATCH 09/11] add test for moisture sensor --- tests/plant_node/Makefile | 8 +++ tests/plant_node/README.md | 12 +++++ tests/plant_node/main.c | 99 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 tests/plant_node/Makefile create mode 100644 tests/plant_node/README.md create mode 100644 tests/plant_node/main.c diff --git a/tests/plant_node/Makefile b/tests/plant_node/Makefile new file mode 100644 index 000000000000..d93a22cfee5e --- /dev/null +++ b/tests/plant_node/Makefile @@ -0,0 +1,8 @@ +APPLICATION = plant_node +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_adc + +USEMODULE += vtimer + +include $(RIOTBASE)/Makefile.include diff --git a/tests/plant_node/README.md b/tests/plant_node/README.md new file mode 100644 index 000000000000..31fc3266d15b --- /dev/null +++ b/tests/plant_node/README.md @@ -0,0 +1,12 @@ +# About +This is a manual test application for the SEN0114 moisture sensor. + +# Usage +This test application will initialize one ADC channel with 12 bit sampling depth and one GPIO which acts as power supply for the sensor, when a measure is taken.After initialization, the sensor value is read in an interval of some seconds and printed to the STDOUT. + +To verify the seen value you can hold the sensor into a glass of water or touch both pins with your hands and see the values are changing. + +# Notes +If using the sensor in your plant pot, you should not set the soil under continous voltage. Also you should not measure more often than "a couple of times" in an hour. + +This test uses timers. Be aware that RIOT timers in the current master may crach after an hour or so! \ No newline at end of file diff --git a/tests/plant_node/main.c b/tests/plant_node/main.c new file mode 100644 index 000000000000..ce3d2798d1fe --- /dev/null +++ b/tests/plant_node/main.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test for the SEN0114 moisture sensor + * + * @author Peter Kietzmann + * + * @} + */ + +#include +#include + +#include "cpu.h" +#include "board.h" +#include "vtimer.h" +#include "periph/adc.h" +#include "periph/gpio.h" + +#if ADC_NUMOF < 1 +#error "Please enable at least 1 ADC device to run this test" +#endif + +#define RES ADC_RES_12BIT +#define ADC_IN_USE ADC_0 +#define ADC_CHANNEL_USE 0 +#define GPIO_POWER_PIN GPIO_0 + +static unsigned int value; + +int main(void) +{ + puts("\nRIOT test for a moisture sensor\n"); + + timex_t sleep1 = timex_set(1, 0); /* 1 sec. */ + timex_t sleep2 = timex_set(1, 0); /* 10 sec. */ + + /* initialize a GPIO that powers the sensor just during a measure */ + printf("Initializing GPIO_%i as power supplying pin", GPIO_POWER_PIN); + if (gpio_init_out(GPIO_POWER_PIN, GPIO_NOPULL) == 0) { + puts(" ...[ok]"); + } + else { + puts(" ...[failed]"); + return 1; + } + puts("\n"); + + /* initialize ADC device */ + printf("Initializing ADC_%i @ %i bit resolution", ADC_IN_USE, (6 + (2* RES))); + if (adc_init(ADC_IN_USE, RES) == 0) { + puts(" ...[ok]"); + } + else { + puts(" ...[failed]"); + return 1; + } + puts("\n"); + + while (1) { + + gpio_set(GPIO_POWER_PIN); + + /* just for safety */ + vtimer_sleep(sleep1); + + value = adc_sample(ADC_IN_USE, ADC_CHANNEL_USE); + + gpio_clear(GPIO_POWER_PIN); + + /* print the result */ + printf("Value: ADC_%i: %4i\n", ADC_IN_USE, value); + + if (value >= 2000) { + puts("Soil is wet"); + } + else if (value > 1000) { + puts("Soil is normal"); + } + else if(value < 1000) { + puts("Soil is dry"); + } + + /* wait for next measure */ + vtimer_sleep(sleep2); + } + + return 0; +} From d37e78bca8a7e6b71ef80756a14212914d3402fe Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 23 Feb 2015 11:27:20 +0100 Subject: [PATCH 10/11] adapt readme --- tests/periph_uart_int/main.c | 2 +- tests/plant_node/README.md | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/periph_uart_int/main.c b/tests/periph_uart_int/main.c index 05c63768fc10..8e5015705b4d 100644 --- a/tests/periph_uart_int/main.c +++ b/tests/periph_uart_int/main.c @@ -42,7 +42,7 @@ /* only build this test if the UART driver is supported */ #if UART_NUMOF -#define DEV UART_1 +#define DEV UART_0 #define BAUD 115200 static volatile int main_pid; diff --git a/tests/plant_node/README.md b/tests/plant_node/README.md index 31fc3266d15b..d478e63c9296 100644 --- a/tests/plant_node/README.md +++ b/tests/plant_node/README.md @@ -9,4 +9,10 @@ To verify the seen value you can hold the sensor into a glass of water or touch # Notes If using the sensor in your plant pot, you should not set the soil under continous voltage. Also you should not measure more often than "a couple of times" in an hour. -This test uses timers. Be aware that RIOT timers in the current master may crach after an hour or so! \ No newline at end of file +This test uses timers. Be aware that RIOT timers in the current master may crach after an hour or so! + +## Notes for samr21-xpro + +You need to change the standard output device from `UART_0` to `UART_1` to free the external ADC reference voltage pin. Then you need to connect an external tty/USB converter to see outputs on your terminal (i.e. pyterm). + +When using the samr21-xpro you need the ADC mode with external reference pin. When this is enabled in the periph.conf.h you need to connect the 3V3 pin with the V_ref pin (on samr21-xpro PA04). \ No newline at end of file From c939182af933d4010382a8bb4da850df9a7f5804 Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 23 Feb 2015 14:08:34 +0100 Subject: [PATCH 11/11] extended readme and minor style ficex --- cpu/samd21/periph/adc.c | 3 --- tests/plant_node/README.md | 10 +++++++++- tests/plant_node/main.c | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/cpu/samd21/periph/adc.c b/cpu/samd21/periph/adc.c index 779d152d24fa..788cd245e32b 100644 --- a/cpu/samd21/periph/adc.c +++ b/cpu/samd21/periph/adc.c @@ -212,9 +212,6 @@ int adc_configure_with_resolution(Adc* adc, uint32_t precision) /* Set Voltage Reference */ adc->REFCTRL.reg = (ADC_0_REF_COM_EN << ADC_REFCTRL_REFCOMP_Pos) | ADC_0_REF_DEFAULT; - int test = adc->REFCTRL.reg; - printf("\nREFCTRL %i\n", test); - switch (precision) { case ADC_0_RES_8BIT: diff --git a/tests/plant_node/README.md b/tests/plant_node/README.md index d478e63c9296..80f2685c8dca 100644 --- a/tests/plant_node/README.md +++ b/tests/plant_node/README.md @@ -15,4 +15,12 @@ This test uses timers. Be aware that RIOT timers in the current master may crach You need to change the standard output device from `UART_0` to `UART_1` to free the external ADC reference voltage pin. Then you need to connect an external tty/USB converter to see outputs on your terminal (i.e. pyterm). -When using the samr21-xpro you need the ADC mode with external reference pin. When this is enabled in the periph.conf.h you need to connect the 3V3 pin with the V_ref pin (on samr21-xpro PA04). \ No newline at end of file +When using the samr21-xpro you need the ADC mode with external reference pin. When this is enabled in the periph.conf.h you need to connect the 3V3 pin with the V_ref pin (on samr21-xpro PA04). + +# Needed pins summary + +- GPIO Power pin - GPIO_0 - PA13 +- ADC input pin - ADC_0_POS_INPUT - PA06 +- ADC ref. pin - ADC_0_REF_DEFAULT - PA04 +- Serial out - UART_1_TX_PIN - PA22 +- Serial int - UART_1_RX_PIN - PA23 \ No newline at end of file diff --git a/tests/plant_node/main.c b/tests/plant_node/main.c index ce3d2798d1fe..d42fe4258c9f 100644 --- a/tests/plant_node/main.c +++ b/tests/plant_node/main.c @@ -43,7 +43,7 @@ int main(void) puts("\nRIOT test for a moisture sensor\n"); timex_t sleep1 = timex_set(1, 0); /* 1 sec. */ - timex_t sleep2 = timex_set(1, 0); /* 10 sec. */ + timex_t sleep2 = timex_set(1, 0); /* 1 sec. */ /* initialize a GPIO that powers the sensor just during a measure */ printf("Initializing GPIO_%i as power supplying pin", GPIO_POWER_PIN); @@ -91,7 +91,7 @@ int main(void) puts("Soil is dry"); } - /* wait for next measure */ + /* wait for next measure */ vtimer_sleep(sleep2); }