diff --git a/os/hal/ports/MSP430X/hal_dma_lld.c b/os/hal/ports/MSP430X/hal_dma_lld.c index 58293ca4..43e1d6cc 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; - } + if (i == MSP430X_DMA_CHANNELS) { + return true; + } #endif - - /* Make the request */ - init_request(request, i); - -#if CH_CFG_USE_SEMAPHORES - chSemSignal(&dma_lock); -#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; - } - - /* Increment the DMA counter */ -#if CH_CFG_USE_SEMAPHORES - 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; -} + /* Make the request */ + init_request(request, i); + + 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; + } + +/* Increment the DMA counter */ +#if CH_CFG_USE_SEMAPHORES + msg_t semresult = chSemWait(&dma_lock); + if (semresult != MSG_OK) + return true; +#endif + + 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;*/ -/** - * @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; - 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 2cce85dd..d1495d26 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 8789ed18..0b6363b3 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 bc002cb3..0d9aa1cd 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 00000000..70a357e3 --- /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 00000000..ebf14c81 --- /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 69477857..832814bb 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/testhal/MSP430X/EXP430FR5969/DMA/Makefile b/testhal/MSP430X/EXP430FR5969/DMA/Makefile index e109c95a..cf81f18b 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 96f45d04..1929af17 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 00000000..cf81f18b --- /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 00000000..cb455266 --- /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 00000000..083e124f --- /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 00000000..17f5c86d --- /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 00000000..5cacf761 --- /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 00000000..8968fb99 --- /dev/null +++ b/testhal/MSP430X/EXP430FR5969/SPI/msp_vectors.c @@ -0,0 +1,316 @@ +#include + +__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) { + } +} + +