diff --git a/demos/MSP430-MSP430x1611-GCC/Makefile b/demos/MSP430-MSP430x1611-GCC/Makefile index 4f9d159c3..8cf693eb1 100644 --- a/demos/MSP430-MSP430x1611-GCC/Makefile +++ b/demos/MSP430-MSP430x1611-GCC/Makefile @@ -45,6 +45,7 @@ include ../../test/test.mk # C sources here. CSRC = ../../ports/MSP430/chcore.c \ ../../ports/MSP430/msp430_serial.c \ + ../../ports/MSP430/pal_lld.c \ ${KERNSRC} \ ${TESTSRC} \ ../../src/lib/evtimer.c \ diff --git a/demos/MSP430-MSP430x1611-GCC/board.c b/demos/MSP430-MSP430x1611-GCC/board.c index c94b4141b..d24bd29e2 100644 --- a/demos/MSP430-MSP430x1611-GCC/board.c +++ b/demos/MSP430-MSP430x1611-GCC/board.c @@ -25,6 +25,19 @@ #include "board.h" #include "msp430_serial.h" +/* + * Digital I/O ports static configuration. + */ +static const MSP430DIOConfig config = +{ + {VAL_P1OUT, VAL_P1DIR}, + {VAL_P2OUT, VAL_P2DIR}, + {VAL_P3OUT, VAL_P3DIR}, + {VAL_P4OUT, VAL_P4DIR}, + {VAL_P5OUT, VAL_P5DIR}, + {VAL_P6OUT, VAL_P6DIR}, +}; + /* * Hardware initialization goes here. * NOTE: Interrupts are still disabled. @@ -47,27 +60,9 @@ void hwinit(void) { BCSCTL2 = VAL_BCSCTL2; /* - * I/O ports initialization. PxSEL registers are assumed to be cleared after - * the reset. + * I/O ports initialization. */ - palInit(); - palWritePort(IOPORT_A, VAL_P1OUT); - pal_lld_msp430_set_direction(IOPORT_A, VAL_P1DIR); - - palWritePort(IOPORT_B, VAL_P2OUT); - pal_lld_msp430_set_direction(IOPORT_B, VAL_P2DIR); - - palWritePort(IOPORT_C, VAL_P3OUT); - pal_lld_msp430_set_direction(IOPORT_C, VAL_P3DIR); - - palWritePort(IOPORT_D, VAL_P4OUT); - pal_lld_msp430_set_direction(IOPORT_D, VAL_P4DIR); - - palWritePort(IOPORT_E, VAL_P5OUT); - pal_lld_msp430_set_direction(IOPORT_E, VAL_P5DIR); - - palWritePort(IOPORT_F, VAL_P6OUT); - pal_lld_msp430_set_direction(IOPORT_F, VAL_P6DIR); + palInit(&config); /* * Timer 0 setup, uses SMCLK as source. diff --git a/ports/MSP430/pal_lld.c b/ports/MSP430/pal_lld.c new file mode 100644 index 000000000..a81b152c8 --- /dev/null +++ b/ports/MSP430/pal_lld.c @@ -0,0 +1,113 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file ports/MSP430/pal_lld.c + * @brief MSP430 Digital I/O low level driver code + * @addtogroup MSP430_PAL + * @{ + */ + +#include +#include + +/** + * @brief MSP430 I/O ports configuration. + * + * @param[in] the MSP430 ports configuration + * + * @note The @p PxIFG, @p PxIE and @p PxSEL registers are cleared. @p PxOUT + * and @p PxDIR are configured as specified. + */ +void _pal_lld_init(const MSP430DIOConfig *config) { + +#if defined(__MSP430_HAS_PORT1__) || defined(__MSP430_HAS_PORT1_R__) + IOPORT_A->iop_full.ie.reg_p = 0; + IOPORT_A->iop_full.ifg.reg_p = 0; + IOPORT_A->iop_full.sel.reg_p = 0; + IOPORT_A->iop_common.out = config->P1Data.out; + IOPORT_A->iop_common.dir = config->P1Data.dir; +#endif + +#if defined(__MSP430_HAS_PORT2__) || defined(__MSP430_HAS_PORT2_R__) + IOPORT_B->iop_full.ie.reg_p = 0; + IOPORT_B->iop_full.ifg.reg_p = 0; + IOPORT_B->iop_full.sel.reg_p = 0; + IOPORT_B->iop_common.out = config->P2Data.out; + IOPORT_B->iop_common.dir = config->P2Data.dir; +#endif + +#if defined(__MSP430_HAS_PORT3__) || defined(__MSP430_HAS_PORT3_R__) + IOPORT_C->iop_simple.sel.reg_p = 0; + IOPORT_C->iop_common.out = config->P3Data.out; + IOPORT_C->iop_common.dir = config->P3Data.dir; +#endif + +#if defined(__MSP430_HAS_PORT4__) || defined(__MSP430_HAS_PORT4_R__) + IOPORT_D->iop_simple.sel.reg_p = 0; + IOPORT_D->iop_common.out = config->P4Data.out; + IOPORT_D->iop_common.dir = config->P4Data.dir; +#endif + +#if defined(__MSP430_HAS_PORT5__) || defined(__MSP430_HAS_PORT5_R__) + IOPORT_E->iop_simple.sel.reg_p = 0; + IOPORT_E->iop_common.out = config->P5Data.out; + IOPORT_E->iop_common.dir = config->P5Data.dir; +#endif + +#if defined(__MSP430_HAS_PORT6__) || defined(__MSP430_HAS_PORT6_R__) + IOPORT_F->iop_simple.sel.reg_p = 0; + IOPORT_F->iop_common.out = config->P6Data.out; + IOPORT_F->iop_common.dir = config->P6Data.dir; +#endif +} + +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the setup mode + * + * @note This function is not meant to be invoked directly by the application + * code. + * @note @p PAL_MODE_UNCONNECTED is implemented as output as recommended by + * the MSP430x1xx Family User's Guide. Unconnected pads are set to + * high logic state by default. + * @note This function does not alter the @p PxSEL registers. Alternate + * functions setup must be handled by device-specific code. + */ +void _pal_lld_setmode(ioportid_t port, ioportmask_t mask, uint_fast8_t mode) { + + switch (mode) { + case PAL_MODE_RESET: + case PAL_MODE_INPUT: + port->iop_common.dir.reg_p &= ~mask; + break; + case PAL_MODE_UNCONNECTED: + port->iop_common.out.reg_p |= mask; + case PAL_MODE_OUTPUT_PUSHPULL: + port->iop_common.dir.reg_p |= mask; + break; + } +} + +/** @} */ diff --git a/ports/MSP430/pal_lld.h b/ports/MSP430/pal_lld.h index cf8a8a62f..940d3f7bd 100644 --- a/ports/MSP430/pal_lld.h +++ b/ports/MSP430/pal_lld.h @@ -19,7 +19,7 @@ /** * @file ports/MSP430/pal_lld.h - * @brief MSP430 Digital I/O low level driver + * @brief MSP430 Digital I/O low level driver header * @addtogroup MSP430_PAL * @{ */ @@ -29,28 +29,103 @@ #include +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ + +#undef PAL_MODE_INPUT_PULLUP +#undef PAL_MODE_INPUT_PULLDOWN +#undef PAL_MODE_OUTPUT_OPENDRAIN + /*===========================================================================*/ /* I/O Ports Types and constants. */ /*===========================================================================*/ +/** + * @brief Simplified MSP430 I/O port representation. + * @details This structure represents the common part of all the MSP430 I/O + * ports. + */ +struct port_common_t { + ioregister_t in; + ioregister_t out; + ioregister_t dir; +}; + /** * @brief Generic MSP430 I/O port. */ union __ioport { - struct { - ioregister_t in; - ioregister_t out; - ioregister_t dir; - } iop_common; + struct port_common_t iop_common; struct port_simple_t iop_simple; struct port_full_t iop_full; }; +/** + * @brief Setup registers common to all the MSP430 ports. + */ +struct port_setup_t { + ioregister_t out; + ioregister_t dir; +}; + +/** + * @brief MSP430 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. + */ +typedef struct { +#if defined(__MSP430_HAS_PORT1__) || \ + defined(__MSP430_HAS_PORT1_R__) || \ + defined(__DOXYGEN__) + /** @brief Port 1 setup data.*/ + struct port_setup_t P1Data; +#endif +#if defined(__MSP430_HAS_PORT2__) || \ + defined(__MSP430_HAS_PORT2_R__) || \ + defined(__DOXYGEN__) + /** @brief Port 2 setup data.*/ + struct port_setup_t P2Data; +#endif +#if defined(__MSP430_HAS_PORT3__) || \ + defined(__MSP430_HAS_PORT3_R__) || \ + defined(__DOXYGEN__) + /** @brief Port 3 setup data.*/ + struct port_setup_t P3Data; +#endif +#if defined(__MSP430_HAS_PORT4__) || \ + defined(__MSP430_HAS_PORT4_R__) || \ + defined(__DOXYGEN__) + /** @brief Port 4 setup data.*/ + struct port_setup_t P4Data; +#endif +#if defined(__MSP430_HAS_PORT5__) || \ + defined(__MSP430_HAS_PORT5_R__) || \ + defined(__DOXYGEN__) + /** @brief Port 5 setup data.*/ + struct port_setup_t P5Data; +#endif +#if defined(__MSP430_HAS_PORT6__) || \ + defined(__MSP430_HAS_PORT6_R__) || \ + defined(__DOXYGEN__) + /** @brief Port 6 setup data.*/ + struct port_setup_t P6Data; +#endif +} MSP430DIOConfig; + /** * @brief Width, in bits, of an I/O port. */ #define PAL_IOPORTS_WIDTH 8 +/** + * @brief Whole port mask. + * @brief This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFF) + /** * @brief Digital I/O port sized unsigned type. */ @@ -135,8 +210,11 @@ typedef union __ioport * ioportid_t; /** * @brief Low level PAL subsystem initialization. + * @details In MSP430 programs all the ports as input. + * + * @param[in] the MSP430 ports configuration */ -#define pal_lld_init() +#define pal_lld_init(config) _pal_lld_init(config) /** * @brief Reads the physical I/O port states. @@ -180,12 +258,31 @@ typedef union __ioport * ioportid_t; } /** - * @brief Set pins direction. - * @details This function programs the pins direction within a port. + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the setup mode + * + * @note This function is not meant to be invoked directly by the application + * code. + * @note @p PAL_MODE_UNCONNECTED is implemented as output as recommended by + * the MSP430x1xx Family User's Guide. + * @note This function does not alter the @p PxSEL registers. Alternate + * functions setup must be handled by device-specific code. */ -#define pal_lld_msp430_set_direction(port, dirmask) { \ - (port)->iop_common.dir.reg_p = (dirmask); \ +#define pal_lld_setmode(port, mask, mode) _pal_lld_setmode(port, mask, mode) + +#ifdef __cplusplus +extern "C" { +#endif + void _pal_lld_init(const MSP430DIOConfig *config); + void _pal_lld_setmode(ioportid_t port, ioportmask_t mask, uint_fast8_t mode); +#ifdef __cplusplus } +#endif #endif /* _PAL_LLD_H_ */ diff --git a/src/lib/pal.c b/src/lib/pal.c index abe3db3f6..95ab43883 100644 --- a/src/lib/pal.c +++ b/src/lib/pal.c @@ -70,4 +70,12 @@ void palWriteBus(IOBus *bus, ioportmask_t bits) { palWriteGroup(bus->bus_portid, bus->bus_mask, bus->bus_offset, bits); } +void palSetBusMode(IOBus *bus, uint_fast8_t mode) { + + chDbgCheck((bus != NULL) && + (bus->bus_offset > PAL_IOPORTS_WIDTH), "palSetBusMode"); + + palSetMode(bus->bus_portid, bus->bus_mask, mode); +} + /** @} */ diff --git a/src/lib/pal.h b/src/lib/pal.h index d4190e500..96ed8c312 100644 --- a/src/lib/pal.h +++ b/src/lib/pal.h @@ -27,6 +27,48 @@ #ifndef _PAL_H_ #define _PAL_H_ +/** + * @brief After reset state. + * @details The state itself is not specified and is architecture dependent, + * it is guaranteed to be equal to the after-reset state. It is + * usually an input state. + */ +#define PAL_MODE_RESET 0 + +/** + * @brief Safe state for unconnected pads. + * @details The state itself is not specified and is architecture dependent, + * it may be mapped on @p PAL_MODE_INPUT_PULLUP, + * @p PAL_MODE_INPUT_PULLDOWN or @p PAL_MODE_OUTPUT_PUSHPULL as + * example. + */ +#define PAL_MODE_UNCONNECTED 1 + +/** + * @brief Regular input high-Z pad. + */ +#define PAL_MODE_INPUT 2 + +/** + * @brief Input pad with weak pull up resistor. + */ +#define PAL_MODE_INPUT_PULLUP 3 + +/** + * @brief Input pad with weak pull down resistor. + */ +#define PAL_MODE_INPUT_PULLDOWN 4 + +/** + * @brief Push-pull output pad. + */ +#define PAL_MODE_OUTPUT_PUSHPULL 5 + +/** + * @brief Open-drain output pad. + */ +#define PAL_MODE_OUTPUT_OPENDRAIN 6 + #ifndef _PAL_LLD_H_ #include "pal_lld.h" #endif @@ -70,7 +112,7 @@ * @param width the bus width in bits * @param offset the bus bit offset within the port */ -#define _IOBUS_DATA(name, port, width, offset) \ +#define _IOBUS_DATA(name, port, width, offset) \ {port, PAL_GROUP_MASK(width), offset} /** @@ -102,9 +144,13 @@ typedef struct { } IOBus; /** - * @brief PAL subsystem initialization. + * @brief PAL subsystem initialization. + * + * @param[in] config pointer to an architecture specific configuration + * structure. This structure is defined in the low level driver + * header. */ -#define palInit() pal_lld_init() +#define palInit(config) pal_lld_init(config) /** * @brief Reads the physical I/O port states. @@ -354,11 +400,29 @@ typedef struct { #define palTogglePad(port, pad) pal_lld_togglepad(port, pad) #endif +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the setup mode + * + * @note Programming an unknown or unsupported mode is silently ignored. + */ +#if !defined(pal_lld_setmode) || defined(__DOXYGEN__) +#define palSetMode(port, mask, mode) +#else +#define palSetMode(port, mask, mode) pal_lld_setmode(port, mask, mode) +#endif + #ifdef __cplusplus extern "C" { #endif ioportmask_t palReadBus(IOBus *bus); void palWriteBus(IOBus *bus, ioportmask_t bits); + void palSetBusMode(IOBus *bus, uint_fast8_t mode); #ifdef __cplusplus } #endif diff --git a/src/templates/pal_lld.h b/src/templates/pal_lld.h index 38d0253e2..48c91811c 100644 --- a/src/templates/pal_lld.h +++ b/src/templates/pal_lld.h @@ -36,6 +36,12 @@ */ #define PAL_IOPORTS_WIDTH 32 +/** + * @brief Whole port mask. + * @brief This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF) + /** * @brief Digital I/O port sized unsigned type. */ @@ -254,6 +260,20 @@ typedef uint32_t ioportid_t; */ #define pal_lld_togglepad(port, pad) +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the setup mode + * + * @note This function is not meant to be invoked directly by the application + * code. + */ +#define pal_lld_setmode(port, mask, mode) + #endif /* _PAL_LLD_H_ */ /** @} */