aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/MSP430X/hal_dma_lld.c
diff options
context:
space:
mode:
authorAndrew Wygle <awygle@gmail.com>2016-05-07 23:35:10 -0700
committerAndrew Wygle <awygle@gmail.com>2016-05-08 17:59:09 -0700
commitdfd93d512b6703ac45d5c0e322bcf8b5e83f50f1 (patch)
tree7a4c49a2e3852905297b85e1452071b1c876cfaa /os/hal/ports/MSP430X/hal_dma_lld.c
parentcf02c79b5aa7209542cbf1b0cefe703a2c0c60be (diff)
downloadChibiOS-Contrib-dfd93d512b6703ac45d5c0e322bcf8b5e83f50f1.tar.gz
ChibiOS-Contrib-dfd93d512b6703ac45d5c0e322bcf8b5e83f50f1.tar.bz2
ChibiOS-Contrib-dfd93d512b6703ac45d5c0e322bcf8b5e83f50f1.zip
Added SPI driver and test code to MSP430X port
A DMA-driven SPI driver and fairly comprehensive test code for SPI on the MSP430X port. Required some cleanup to the DMA and Serial drivers as well. Includes some reformatting to be more in line with ChibiOS coding standards.
Diffstat (limited to 'os/hal/ports/MSP430X/hal_dma_lld.c')
-rw-r--r--os/hal/ports/MSP430X/hal_dma_lld.c253
1 files changed, 134 insertions, 119 deletions
diff --git a/os/hal/ports/MSP430X/hal_dma_lld.c b/os/hal/ports/MSP430X/hal_dma_lld.c
index 58293ca..43e1d6c 100644
--- a/os/hal/ports/MSP430X/hal_dma_lld.c
+++ b/os/hal/ports/MSP430X/hal_dma_lld.c
@@ -40,9 +40,8 @@
/* Driver local variables and types. */
/*===========================================================================*/
-/* TODO make sure this is right... */
-static msp430x_dma_ch_reg_t * const dma_channels = (msp430x_dma_ch_reg_t *)&DMA0CTL;
-static uint8_t * const dma_ctls = (uint8_t *)&DMACTL0;
+static msp430x_dma_ch_reg_t * const dma_channels =
+ (msp430x_dma_ch_reg_t *)&DMA0CTL;
static msp430x_dma_cb_t callbacks[MSP430X_DMA_CHANNELS];
#if CH_CFG_USE_SEMAPHORES
@@ -53,16 +52,29 @@ static semaphore_t dma_lock;
/* Driver local functions. */
/*===========================================================================*/
+/**
+ * @brief Set a DMA trigger using an index.
+ *
+ * @param[in] index The index of the DMA channel whose trigger is set.
+ * @param[in] trigger The trigger to use.
+ * @note This is all to get around weird MSP behavior when writing to memory-
+ * mapped registers using bytewise instructions.
+ */
+static void dma_trigger_set(uint8_t index, uint8_t trigger) {
+ uint16_t * ctl = ((uint16_t *)((uintptr_t)(&DMACTL0)) + (index / 2));
+ *ctl &= 0xFF00 >> (8 * (index % 2));
+ *ctl |= trigger << (8 * (index % 2));
+}
static void init_request(const msp430x_dma_req_t * request, uint8_t index) {
-
- dma_ctls[index] = request->trigger;
- callbacks[index] = request->callback;
- msp430x_dma_ch_reg_t * ch = &dma_channels[index];
- ch->sa = (uintptr_t)request->source_addr;
- ch->da = (uintptr_t)request->dest_addr;
- ch->sz = request->size;
- ch->ctl = DMAREQ | DMAIE | DMAEN | request->data_mode | request->addr_mode
- | request->transfer_mode;
+
+ dma_trigger_set(index, request->trigger);
+ callbacks[index] = request->callback;
+ msp430x_dma_ch_reg_t * ch = &dma_channels[index];
+ ch->sa = (uintptr_t)request->source_addr;
+ ch->da = (uintptr_t)request->dest_addr;
+ ch->sz = request->size;
+ ch->ctl = DMAREQ | DMAIE | DMAEN | request->data_mode | request->addr_mode |
+ request->transfer_mode;
}
/*===========================================================================*/
@@ -72,19 +84,22 @@ static void init_request(const msp430x_dma_req_t * request, uint8_t index) {
PORT_IRQ_HANDLER(DMA_VECTOR) {
uint8_t index;
OSAL_IRQ_PROLOGUE();
-
+
index = (DMAIV >> 1) - 1;
-
+
if (index < MSP430X_DMA_CHANNELS) {
+#if CH_CFG_USE_SEMAPHORES
+ chSemSignalI(&dma_lock);
+#endif
+
msp430x_dma_cb_t * cb = &callbacks[index];
-
+
/* WARNING: CALLBACKS ARE CALLED IN AN ISR CONTEXT! */
if (cb->callback != NULL) {
cb->callback(cb->args);
}
-
- }
-
+ }
+
OSAL_IRQ_EPILOGUE();
}
@@ -94,7 +109,7 @@ PORT_IRQ_HANDLER(DMA_VECTOR) {
/**
* @brief Initialize the DMA engine.
- *
+ *
* @init
*/
void dmaInit(void) {
@@ -112,132 +127,132 @@ void dmaInit(void) {
* disabled, the calling thread will busy-wait instead of sleeping.
*/
bool dmaRequest(msp430x_dma_req_t * request, systime_t timeout) {
- /* Check if a DMA channel is available */
+/* Check if a DMA channel is available */
#if CH_CFG_USE_SEMAPHORES
msg_t semresult = chSemWaitTimeout(&dma_lock, timeout);
if (semresult != MSG_OK)
return true;
#endif
-
+
#if !(CH_CFG_USE_SEMAPHORES)
systime_t start = chVTGetSystemTimeX();
-
+
do {
#endif
- /* Grab the correct DMA channel to use */
- int i = 0;
- for (i = 0; i < MSP430X_DMA_CHANNELS; i++) {
- if (!(dma_channels[i].ctl & DMAEN)) {
- break;
+ /* Grab the correct DMA channel to use */
+ int i = 0;
+ for (i = 0; i < MSP430X_DMA_CHANNELS; i++) {
+ if (!(dma_channels[i].ctl & DMAEN)) {
+ break;
+ }
}
- }
#if !(CH_CFG_USE_SEMAPHORES)
- while (chVTTimeElapsedSinceX(start) < timeout);
+ while (chVTTimeElapsedSinceX(start) < timeout)
+ ;
#endif
-
+
#if !(CH_CFG_USE_SEMAPHORES)
- if (i == MSP430X_DMA_CHANNELS) {
- return true;
- }
-#endif
-
- /* Make the request */
- init_request(request, i);
-
-#if CH_CFG_USE_SEMAPHORES
- chSemSignal(&dma_lock);
+ if (i == MSP430X_DMA_CHANNELS) {
+ return true;
+ }
#endif
-
- return false;
-}
-/**
- * @brief Acquires exclusive control of a DMA channel.
- * @pre The channel must not be already acquired or an error is returned.
- * @note If the channel is in use by the DMA engine, blocks until acquired.
- * @post This channel must be interacted with using only the functions
- * defined in this module.
- *
- * @param[out] channel The channel handle. Must be pre-allocated.
- * @param[in] index The index of the channel (< MSP430X_DMA_CHANNELS).
- * @return The operation status.
- * @retval false no error, channel acquired.
- * @retval true error, channel already acquired.
- */
-bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index) {
- /* Acquire the channel in an idle mode */
-
- /* Is the channel already acquired? */
- osalDbgAssert(index < MSP430X_DMA_CHANNELS, "invalid channel index");
- if (dma_channels[index].ctl & DMADT_4) {
- return true;
+ /* Make the request */
+ init_request(request, i);
+
+ return false;
}
-
- /* Increment the DMA counter */
+
+ /**
+ * @brief Acquires exclusive control of a DMA channel.
+ * @pre The channel must not be already acquired or an error is returned.
+ * @note If the channel is in use by the DMA engine, blocks until acquired.
+ * @post This channel must be interacted with using only the functions
+ * defined in this module.
+ *
+ * @param[out] channel The channel handle. Must be pre-allocated.
+ * @param[in] index The index of the channel (< MSP430X_DMA_CHANNELS).
+ * @return The operation status.
+ * @retval false no error, channel acquired.
+ * @retval true error, channel already acquired.
+ */
+ bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index) {
+ /* Acquire the channel in an idle mode */
+
+ /* Is the channel already acquired? */
+ osalDbgAssert(index < MSP430X_DMA_CHANNELS, "invalid channel index");
+ if (dma_channels[index].ctl & DMADT_4) {
+ return true;
+ }
+
+/* Increment the DMA counter */
#if CH_CFG_USE_SEMAPHORES
- msg_t semresult = chSemWait(&dma_lock);
- if (semresult != MSG_OK)
- return true;
+ msg_t semresult = chSemWait(&dma_lock);
+ if (semresult != MSG_OK)
+ return true;
#endif
-
- while (dma_channels[index].ctl & DMAEN) ;
-
- dma_ctls[index] = DMA_TRIGGER_MNEM(DMAREQ);
- dma_channels[index].sz = 0;
- dma_channels[index].ctl = DMAEN | DMAABORT | DMADT_4;
-
- channel->registers = dma_channels + index;
- channel->ctl = dma_ctls + index;
- channel->cb = callbacks + index;
-
- return false;
-}
-/**
- * @brief Initiates a DMA transfer operation using an acquired channel.
- * @pre The channel must have been acquired using @p dmaAcquire().
- *
- * @param[in] channel pointer to a DMA channel from @p dmaAcquire().
- * @param[in] request pointer to a DMA request object.
- */
-void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request) {
-
- *(channel->ctl) = request->trigger;
-
+ while (dma_channels[index].ctl & DMAEN)
+ ;
+
+ dma_trigger_set(index, DMA_TRIGGER_MNEM(DMAREQ));
+ dma_channels[index].sz = 0;
+ dma_channels[index].ctl = DMAEN | DMAABORT | DMADT_4;
+
+ channel->registers = dma_channels + index;
+ channel->index = index;
+ channel->cb = callbacks + index;
+
+ return false;
+ }
+
+ /**
+ * @brief Initiates a DMA transfer operation using an acquired channel.
+ * @pre The channel must have been acquired using @p dmaAcquire().
+ *
+ * @param[in] channel pointer to a DMA channel from @p dmaAcquire().
+ * @param[in] request pointer to a DMA request object.
+ */
+ void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request) {
+
+ dma_trigger_set(channel->index, request->trigger);
+ /**(channel->ctl) = request->trigger;*/
+
channel->cb->callback = request->callback.callback;
- channel->cb->args = request->callback.args;
-
+ channel->cb->args = request->callback.args;
+
chSysLock();
channel->registers->ctl &= (~DMAEN);
- channel->registers->sa = (uintptr_t)request->source_addr;
- channel->registers->da = (uintptr_t)request->dest_addr;
- channel->registers->sz = request->size;
- channel->registers->ctl = DMAIE | request->data_mode | request->addr_mode
- | request->transfer_mode | DMADT_4 | DMAEN | DMAREQ; /* repeated transfers */
+ channel->registers->sa = (uintptr_t)request->source_addr;
+ channel->registers->da = (uintptr_t)request->dest_addr;
+ channel->registers->sz = request->size;
+ channel->registers->ctl = DMAIE | request->data_mode | request->addr_mode |
+ request->transfer_mode | DMADT_4 | DMAEN |
+ DMAREQ; /* repeated transfers */
chSysUnlock();
-}
+ }
-/**
- * @brief Releases exclusive control of a DMA channel.
- * @details The channel is released from control and returned to the DMA engine
- * pool. Trying to release an unallocated channel is an illegal
- * operation and is trapped if assertions are enabled.
- * @pre The channel must have been acquired using @p dmaAcquire().
- * @post The channel is returned to the DMA engine pool.
- */
-void dmaRelease(msp430x_dma_ch_t * channel) {
-
- osalDbgCheck(channel != NULL);
- osalDbgAssert(channel->registers->ctl & DMADT_4, "not acquired");
-
- /* Release the channel in an idle mode */
- channel->registers->ctl = DMAABORT;
-
- /* release the DMA counter */
+ /**
+ * @brief Releases exclusive control of a DMA channel.
+ * @details The channel is released from control and returned to the DMA
+ * engine
+ * pool. Trying to release an unallocated channel is an illegal
+ * operation and is trapped if assertions are enabled.
+ * @pre The channel must have been acquired using @p dmaAcquire().
+ * @post The channel is returned to the DMA engine pool.
+ */
+ void dmaRelease(msp430x_dma_ch_t * channel) {
+
+ osalDbgCheck(channel != NULL);
+
+ /* Release the channel in an idle mode */
+ channel->registers->ctl = DMAABORT;
+
+/* release the DMA counter */
#if CH_CFG_USE_SEMAPHORES
- chSemSignal(&dma_lock);
+ chSemSignal(&dma_lock);
#endif
-}
+ }
#endif /* HAL_USE_DMA == TRUE */