Merge pull request #70 from awygle/msp430x
Added SPI driver and test code to MSP430X port
This commit is contained in:
commit
de959be01f
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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_ */
|
|
@ -0,0 +1,316 @@
|
|||
#include <msp430.h>
|
||||
|
||||
__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) {
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue