aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/MSP430X
diff options
context:
space:
mode:
authorawygle <awygle@gmail.com>2016-05-04 23:47:33 -0700
committerawygle <awygle@gmail.com>2016-05-04 23:47:33 -0700
commitcf02c79b5aa7209542cbf1b0cefe703a2c0c60be (patch)
tree0557b4194870b710411fbddaf1c58eb432e2d0d4 /os/hal/ports/MSP430X
parentfe1d3f21146b1d28bd281b3682a528042b80253c (diff)
downloadChibiOS-Contrib-cf02c79b5aa7209542cbf1b0cefe703a2c0c60be.tar.gz
ChibiOS-Contrib-cf02c79b5aa7209542cbf1b0cefe703a2c0c60be.tar.bz2
ChibiOS-Contrib-cf02c79b5aa7209542cbf1b0cefe703a2c0c60be.zip
Merge pull request #68 from awygle/msp430x
MSP430X DMA Support, EXP430FR6989 Demo + Makefile Updates
Diffstat (limited to 'os/hal/ports/MSP430X')
-rw-r--r--os/hal/ports/MSP430X/hal_dma_lld.c244
-rw-r--r--os/hal/ports/MSP430X/hal_dma_lld.h174
-rw-r--r--os/hal/ports/MSP430X/hal_pal_lld.c14
-rw-r--r--os/hal/ports/MSP430X/hal_serial_lld.c6
-rw-r--r--os/hal/ports/MSP430X/platform.mk3
5 files changed, 437 insertions, 4 deletions
diff --git a/os/hal/ports/MSP430X/hal_dma_lld.c b/os/hal/ports/MSP430X/hal_dma_lld.c
new file mode 100644
index 0000000..58293ca
--- /dev/null
+++ b/os/hal/ports/MSP430X/hal_dma_lld.c
@@ -0,0 +1,244 @@
+/*
+ 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 MSP430X hal_dma_lld.c
+ * @brief MSP430X DMA subsystem low level driver source.
+ *
+ * @addtogroup MSP430X_DMA
+ * @{
+ */
+
+#include "hal.h"
+#include "ch.h"
+#include "hal_dma_lld.h"
+
+#if (HAL_USE_DMA == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* 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_cb_t callbacks[MSP430X_DMA_CHANNELS];
+#if CH_CFG_USE_SEMAPHORES
+static semaphore_t dma_lock;
+#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+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;
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+PORT_IRQ_HANDLER(DMA_VECTOR) {
+ uint8_t index;
+ OSAL_IRQ_PROLOGUE();
+
+ index = (DMAIV >> 1) - 1;
+
+ if (index < MSP430X_DMA_CHANNELS) {
+ 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();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Initialize the DMA engine.
+ *
+ * @init
+ */
+void dmaInit(void) {
+#if CH_CFG_USE_SEMAPHORES
+ chSemObjectInit(&dma_lock, MSP430X_DMA_CHANNELS);
+#endif
+}
+
+/**
+ * @brief Requests a DMA transfer operation from the DMA engine.
+ * @note The DMA engine uses unclaimed DMA channels to provide DMA services
+ * for one-off or infrequent uses. If all channels are busy, and
+ * semaphores are enabled, the calling thread will sleep until a
+ * channel is available or the request times out. If semaphores are
+ * 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 */
+#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;
+ }
+ }
+#if !(CH_CFG_USE_SEMAPHORES)
+ while (chVTTimeElapsedSinceX(start) < timeout);
+#endif
+
+#if !(CH_CFG_USE_SEMAPHORES)
+ if (i == MSP430X_DMA_CHANNELS) {
+ return true;
+ }
+#endif
+
+ /* Make the request */
+ init_request(request, i);
+
+#if CH_CFG_USE_SEMAPHORES
+ chSemSignal(&dma_lock);
+#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;
+}
+
+/**
+ * @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;
+
+ 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 */
+ 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 */
+#if CH_CFG_USE_SEMAPHORES
+ 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
new file mode 100644
index 0000000..2cce85d
--- /dev/null
+++ b/os/hal/ports/MSP430X/hal_dma_lld.h
@@ -0,0 +1,174 @@
+/*
+ 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 MSP430X/hal_dma_lld.c
+ * @brief MSP430X DMA subsystem low level driver header.
+ * @note This driver is used as a DMA engine for the other
+ * low level drivers.
+ *
+ * @addtogroup MSP430X_DMA
+ * @{
+ */
+
+#ifndef HAL_MSP430X_DMA_H
+#define HAL_MSP430X_DMA_H
+
+#if (HAL_USE_DMA == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+#define MSP430X_DMA_SINGLE DMADT_0
+#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_SRCBYTE DMASRCBYTE
+#define MSP430X_DMA_DSTBYTE DMADSTBYTE
+#define MSP430X_DMA_SRCWORD 0
+#define MSP430X_DMA_DSTWORD 0
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#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."
+#endif
+
+#if defined(__MSP430_HAS_DMAX_1__) || defined(__MSP430X_HAS_DMA_1__)
+#define MSP430X_DMA_CHANNELS 1
+#elif defined(__MSP430_HAS_DMAX_3__) || defined(__MSP430X_HAS_DMA_3__)
+#define MSP430X_DMA_CHANNELS 3
+#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?"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of DMA callback function pointer.
+ */
+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_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 */
+} msp430x_dma_req_t;
+
+/**
+ * @brief MSP430X DMA channel register structure.
+ */
+typedef struct {
+ volatile uint16_t ctl; /**< @brief Control register */
+ volatile uint32_t sa; /**< @brief Source address register */
+ volatile uint32_t da; /**< @brief Destination address register */
+ volatile uint16_t sz; /**< @brief Size register */
+ volatile uint16_t pad1;
+ volatile uint16_t pad2;
+} msp430x_dma_ch_reg_t;
+
+/**
+ * @brief MSP430X DMA controller register structure.
+ */
+typedef struct {
+ volatile uint8_t tsel0; /**< @brief Trigger select for channel 0 */
+ volatile uint8_t tsel1; /**< @brief Trigger select for channel 1 */
+ volatile uint8_t tsel2; /**< @brief Trigger select for channel 2 */
+ volatile uint8_t tsel3; /**< @brief Trigger select for channel 3 */
+ volatile uint8_t tsel4; /**< @brief Trigger select for channel 4 */
+ volatile uint8_t tsel5; /**< @brief Trigger select for channel 5 */
+ volatile uint8_t tsel6; /**< @brief Trigger select for channel 6 */
+ volatile uint8_t tsel7; /**< @brief Trigger select for channel 7 */
+ volatile uint16_t ctl4; /**< @brief Controller register 4 */
+} msp430x_dma_ctl_reg_t;
+
+/**
+ * @brief MSP430X DMA channel structure.
+ */
+typedef struct {
+ msp430x_dma_ch_reg_t * registers; /**< @brief Pointer to channel registers */
+ volatile uint8_t * ctl; /**< @brief Pointer to channel control register */
+ msp430x_dma_cb_t * cb; /**< @brief Pointer to callback function and args */
+} msp430x_dma_ch_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @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
+
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_DMA == true */
+
+#endif /* HAL_MSP430X_DMA_H */
+
diff --git a/os/hal/ports/MSP430X/hal_pal_lld.c b/os/hal/ports/MSP430X/hal_pal_lld.c
index 4cfff3b..97ad170 100644
--- a/os/hal/ports/MSP430X/hal_pal_lld.c
+++ b/os/hal/ports/MSP430X/hal_pal_lld.c
@@ -68,6 +68,7 @@ void _pal_lld_init(const PALConfig *config) {
PASEL1 = config->porta.sel1;
PAIES = config->porta.ies;
PAIE = config->porta.ie;
+ PAIFG = 0;
#endif
#if defined(PB_BASE) || defined(__DOXYGEN__)
PBOUT = config->portb.out;
@@ -77,6 +78,7 @@ void _pal_lld_init(const PALConfig *config) {
PBSEL1 = config->portb.sel1;
PBIES = config->portb.ies;
PBIE = config->portb.ie;
+ PBIFG = 0;
#endif
#if defined(PC_BASE) || defined(__DOXYGEN__)
PCOUT = config->portc.out;
@@ -84,8 +86,11 @@ void _pal_lld_init(const PALConfig *config) {
PCREN = config->portc.ren;
PCSEL0 = config->portc.sel0;
PCSEL1 = config->portc.sel1;
+#if defined(PCIE) || defined(__DOXYGEN__)
PCIES = config->portc.ies;
PCIE = config->portc.ie;
+ PCIFG = 0;
+#endif
#endif
#if defined(PD_BASE) || defined(__DOXYGEN__)
PDOUT = config->portd.out;
@@ -93,8 +98,11 @@ void _pal_lld_init(const PALConfig *config) {
PDREN = config->portd.ren;
PDSEL0 = config->portd.sel0;
PDSEL1 = config->portd.sel1;
+#if defined(PDIE) || defined(__DOXYGEN__)
PDIES = config->portd.ies;
PDIE = config->portd.ie;
+ PDIFG = 0;
+#endif
#endif
#if defined(PE_BASE) || defined(__DOXYGEN__)
PEOUT = config->porte.out;
@@ -102,8 +110,11 @@ void _pal_lld_init(const PALConfig *config) {
PEREN = config->porte.ren;
PESEL0 = config->porte.sel0;
PESEL1 = config->porte.sel1;
+#if defined(PEIE) || defined(__DOXYGEN__)
PEIES = config->porte.ies;
PEIE = config->porte.ie;
+ PEIFG = 0;
+#endif
#endif
#if defined(PF_BASE) || defined(__DOXYGEN__)
PFOUT = config->portf.out;
@@ -111,8 +122,11 @@ void _pal_lld_init(const PALConfig *config) {
PFREN = config->portf.ren;
PFSEL0 = config->portf.sel0;
PFSEL1 = config->portf.sel1;
+#if defined(PFIE) || defined(__DOXYGEN__)
PFIES = config->portf.ies;
PFIE = config->portf.ie;
+ PFIFG = 0;
+#endif
#endif
PJOUT = config->portj.out;
PJDIR = config->portj.dir;
diff --git a/os/hal/ports/MSP430X/hal_serial_lld.c b/os/hal/ports/MSP430X/hal_serial_lld.c
index 277f6d2..bc002cb 100644
--- a/os/hal/ports/MSP430X/hal_serial_lld.c
+++ b/os/hal/ports/MSP430X/hal_serial_lld.c
@@ -223,10 +223,10 @@ static void usart1_init(const SerialConfig *config) {
UCA1STATW = 0;
UCA1ABCTL = 0;
UCA1IRCTL = 0;
- UCA1IE = UCRXIE;
UCA1CTLW0 = (MSP430X_USART1_PARITY << 14) | (MSP430X_USART1_ORDER << 13) | \
(MSP430X_USART1_SIZE << 12) | (MSP430X_USART1_STOP << 11) | \
(MSP430X_USART1_UCSSEL);
+ UCA1IE = UCRXIE;
}
#endif
@@ -237,10 +237,10 @@ static void usart2_init(const SerialConfig *config) {
UCA2STATW = 0;
UCA2ABCTL = 0;
UCA2IRCTL = 0;
- UCA2IE = UCRXIE;
UCA2CTLW0 = (MSP430X_USART2_PARITY << 14) | (MSP430X_USART2_ORDER << 13) | \
(MSP430X_USART2_SIZE << 12) | (MSP430X_USART2_STOP << 11) | \
(MSP430X_USART2_UCSSEL);
+ UCA2IE = UCRXIE;
}
#endif
@@ -251,10 +251,10 @@ static void usart3_init(const SerialConfig *config) {
UCA3STATW = 0;
UCA3ABCTL = 0;
UCA3IRCTL = 0;
- UCA3IE = UCRXIE;
UCA3CTLW0 = (MSP430X_USART3_PARITY << 14) | (MSP430X_USART3_ORDER << 13) | \
(MSP430X_USART3_SIZE << 12) | (MSP430X_USART3_STOP << 11) | \
(MSP430X_USART3_UCSSEL);
+ UCA3IE = UCRXIE;
}
#endif
diff --git a/os/hal/ports/MSP430X/platform.mk b/os/hal/ports/MSP430X/platform.mk
index b0f256e..6947785 100644
--- a/os/hal/ports/MSP430X/platform.mk
+++ b/os/hal/ports/MSP430X/platform.mk
@@ -2,7 +2,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_pal_lld.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_dma_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X