diff options
Diffstat (limited to 'os')
| -rw-r--r-- | os/hal/ports/MSP430X/hal_dma_lld.c | 253 | ||||
| -rw-r--r-- | os/hal/ports/MSP430X/hal_dma_lld.h | 67 | ||||
| -rw-r--r-- | os/hal/ports/MSP430X/hal_pal_lld.h | 51 | ||||
| -rw-r--r-- | os/hal/ports/MSP430X/hal_serial_lld.c | 483 | ||||
| -rw-r--r-- | os/hal/ports/MSP430X/hal_spi_lld.c | 578 | ||||
| -rw-r--r-- | os/hal/ports/MSP430X/hal_spi_lld.h | 642 | ||||
| -rw-r--r-- | os/hal/ports/MSP430X/platform.mk | 3 | 
7 files changed, 1659 insertions, 418 deletions
| diff --git a/os/hal/ports/MSP430X/hal_dma_lld.c b/os/hal/ports/MSP430X/hal_dma_lld.c index 58293ca..43e1d6c 100644 --- a/os/hal/ports/MSP430X/hal_dma_lld.c +++ b/os/hal/ports/MSP430X/hal_dma_lld.c @@ -40,9 +40,8 @@  /* Driver local variables and types.                                         */
  /*===========================================================================*/
 -/* TODO make sure this is right... */
 -static msp430x_dma_ch_reg_t * const dma_channels = (msp430x_dma_ch_reg_t *)&DMA0CTL;
 -static uint8_t * const dma_ctls = (uint8_t *)&DMACTL0;
 +static msp430x_dma_ch_reg_t * const dma_channels =
 +    (msp430x_dma_ch_reg_t *)&DMA0CTL;
  static msp430x_dma_cb_t callbacks[MSP430X_DMA_CHANNELS];
  #if CH_CFG_USE_SEMAPHORES
 @@ -53,16 +52,29 @@ static semaphore_t dma_lock;  /* Driver local functions.                                                   */
  /*===========================================================================*/
 +/**
 + * @brief     Set a DMA trigger using an index.
 + *
 + * @param[in] index   The index of the DMA channel whose trigger is set.
 + * @param[in] trigger The trigger to use.
 + * @note  This is all to get around weird MSP behavior when writing to memory-
 + *        mapped registers using bytewise instructions.
 + */
 +static void dma_trigger_set(uint8_t index, uint8_t trigger) {
 +  uint16_t * ctl = ((uint16_t *)((uintptr_t)(&DMACTL0)) + (index / 2));
 +  *ctl &= 0xFF00 >> (8 * (index % 2));
 +  *ctl |= trigger << (8 * (index % 2));
 +}
  static void init_request(const msp430x_dma_req_t * request, uint8_t index) {
 -  
 -    dma_ctls[index] = request->trigger;
 -    callbacks[index] = request->callback;
 -    msp430x_dma_ch_reg_t * ch = &dma_channels[index];
 -    ch->sa = (uintptr_t)request->source_addr;
 -    ch->da = (uintptr_t)request->dest_addr;
 -    ch->sz = request->size;
 -    ch->ctl = DMAREQ | DMAIE | DMAEN | request->data_mode | request->addr_mode
 -      | request->transfer_mode; 
 +
 +  dma_trigger_set(index, request->trigger);
 +  callbacks[index]          = request->callback;
 +  msp430x_dma_ch_reg_t * ch = &dma_channels[index];
 +  ch->sa                    = (uintptr_t)request->source_addr;
 +  ch->da                    = (uintptr_t)request->dest_addr;
 +  ch->sz                    = request->size;
 +  ch->ctl = DMAREQ | DMAIE | DMAEN | request->data_mode | request->addr_mode |
 +            request->transfer_mode;
  }
  /*===========================================================================*/
 @@ -72,19 +84,22 @@ static void init_request(const msp430x_dma_req_t * request, uint8_t index) {  PORT_IRQ_HANDLER(DMA_VECTOR) {
    uint8_t index;
    OSAL_IRQ_PROLOGUE();
 -  
 +
    index = (DMAIV >> 1) - 1;
 -  
 +
    if (index < MSP430X_DMA_CHANNELS) {
 +#if CH_CFG_USE_SEMAPHORES
 +    chSemSignalI(&dma_lock);
 +#endif
 +
      msp430x_dma_cb_t * cb = &callbacks[index];
 -    
 +
      /* WARNING: CALLBACKS ARE CALLED IN AN ISR CONTEXT! */
      if (cb->callback != NULL) {
        cb->callback(cb->args);
      }
 -  
 -  } 
 -  
 +  }
 +
    OSAL_IRQ_EPILOGUE();
  }
 @@ -94,7 +109,7 @@ PORT_IRQ_HANDLER(DMA_VECTOR) {  /**
   * @brief Initialize the DMA engine.
 - * 
 + *
   * @init
   */
  void dmaInit(void) {
 @@ -112,132 +127,132 @@ void dmaInit(void) {   *          disabled, the calling thread will busy-wait instead of sleeping.
   */
  bool dmaRequest(msp430x_dma_req_t * request, systime_t timeout) {
 -  /* Check if a DMA channel is available */
 +/* Check if a DMA channel is available */
  #if CH_CFG_USE_SEMAPHORES
    msg_t semresult = chSemWaitTimeout(&dma_lock, timeout);
    if (semresult != MSG_OK)
      return true;
  #endif
 -  
 +
  #if !(CH_CFG_USE_SEMAPHORES)
    systime_t start = chVTGetSystemTimeX();
 -  
 +
    do {
  #endif
 -  /* Grab the correct DMA channel to use */
 -  int i = 0;
 -  for (i = 0; i < MSP430X_DMA_CHANNELS; i++) {
 -    if (!(dma_channels[i].ctl & DMAEN)) {
 -      break;
 +    /* Grab the correct DMA channel to use */
 +    int i = 0;
 +    for (i = 0; i < MSP430X_DMA_CHANNELS; i++) {
 +      if (!(dma_channels[i].ctl & DMAEN)) {
 +        break;
 +      }
      }
 -  }
  #if !(CH_CFG_USE_SEMAPHORES)
 -  while (chVTTimeElapsedSinceX(start) < timeout);
 +    while (chVTTimeElapsedSinceX(start) < timeout)
 +      ;
  #endif
 -  
 +
  #if !(CH_CFG_USE_SEMAPHORES)
 -  if (i == MSP430X_DMA_CHANNELS) {
 -    return true;
 -  }
 -#endif
 -  
 -  /* Make the request */
 -  init_request(request, i);
 -  
 -#if CH_CFG_USE_SEMAPHORES
 -  chSemSignal(&dma_lock);
 +    if (i == MSP430X_DMA_CHANNELS) {
 +      return true;
 +    }
  #endif
 -  
 -  return false;
 -}
 -/**
 - * @brief   Acquires exclusive control of a DMA channel.
 - * @pre     The channel must not be already acquired or an error is returned.
 - * @note    If the channel is in use by the DMA engine, blocks until acquired.
 - * @post    This channel must be interacted with using only the functions 
 - *          defined in this module.
 - *          
 - * @param[out] channel    The channel handle. Must be pre-allocated.
 - * @param[in]  index      The index of the channel (< MSP430X_DMA_CHANNELS).
 - * @return                The operation status.
 - * @retval false          no error, channel acquired.
 - * @retval true           error, channel already acquired.
 - */
 -bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index) {
 -  /* Acquire the channel in an idle mode */
 -  
 -  /* Is the channel already acquired? */
 -  osalDbgAssert(index < MSP430X_DMA_CHANNELS, "invalid channel index");
 -  if (dma_channels[index].ctl & DMADT_4) {
 -    return true;
 +    /* Make the request */
 +    init_request(request, i);
 +
 +    return false;
    }
 -  
 -  /* Increment the DMA counter */
 +
 +  /**
 +   * @brief   Acquires exclusive control of a DMA channel.
 +   * @pre     The channel must not be already acquired or an error is returned.
 +   * @note    If the channel is in use by the DMA engine, blocks until acquired.
 +   * @post    This channel must be interacted with using only the functions
 +   *          defined in this module.
 +   *
 +   * @param[out] channel    The channel handle. Must be pre-allocated.
 +   * @param[in]  index      The index of the channel (< MSP430X_DMA_CHANNELS).
 +   * @return                The operation status.
 +   * @retval false          no error, channel acquired.
 +   * @retval true           error, channel already acquired.
 +   */
 +  bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index) {
 +    /* Acquire the channel in an idle mode */
 +
 +    /* Is the channel already acquired? */
 +    osalDbgAssert(index < MSP430X_DMA_CHANNELS, "invalid channel index");
 +    if (dma_channels[index].ctl & DMADT_4) {
 +      return true;
 +    }
 +
 +/* Increment the DMA counter */
  #if CH_CFG_USE_SEMAPHORES
 -  msg_t semresult = chSemWait(&dma_lock);
 -  if (semresult != MSG_OK)
 -    return true;
 +    msg_t semresult = chSemWait(&dma_lock);
 +    if (semresult != MSG_OK)
 +      return true;
  #endif
 -  
 -  while (dma_channels[index].ctl & DMAEN) ;
 -  
 -  dma_ctls[index] = DMA_TRIGGER_MNEM(DMAREQ);
 -  dma_channels[index].sz = 0;
 -  dma_channels[index].ctl = DMAEN | DMAABORT | DMADT_4;
 -  
 -  channel->registers = dma_channels + index;
 -  channel->ctl = dma_ctls + index;
 -  channel->cb = callbacks + index;
 -  
 -  return false;
 -}
 -/**
 - * @brief   Initiates a DMA transfer operation using an acquired channel.
 - * @pre     The channel must have been acquired using @p dmaAcquire().
 - * 
 - * @param[in] channel   pointer to a DMA channel from @p dmaAcquire().
 - * @param[in] request   pointer to a DMA request object.
 - */
 -void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request) {
 -  
 -    *(channel->ctl) = request->trigger;
 -    
 +    while (dma_channels[index].ctl & DMAEN)
 +      ;
 +
 +    dma_trigger_set(index, DMA_TRIGGER_MNEM(DMAREQ));
 +    dma_channels[index].sz  = 0;
 +    dma_channels[index].ctl = DMAEN | DMAABORT | DMADT_4;
 +
 +    channel->registers = dma_channels + index;
 +    channel->index     = index;
 +    channel->cb        = callbacks + index;
 +
 +    return false;
 +  }
 +
 +  /**
 +   * @brief   Initiates a DMA transfer operation using an acquired channel.
 +   * @pre     The channel must have been acquired using @p dmaAcquire().
 +   *
 +   * @param[in] channel   pointer to a DMA channel from @p dmaAcquire().
 +   * @param[in] request   pointer to a DMA request object.
 +   */
 +  void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request) {
 +
 +    dma_trigger_set(channel->index, request->trigger);
 +    /**(channel->ctl) = request->trigger;*/
 +
      channel->cb->callback = request->callback.callback;
 -    channel->cb->args = request->callback.args;
 -    
 +    channel->cb->args     = request->callback.args;
 +
      chSysLock();
      channel->registers->ctl &= (~DMAEN);
 -    channel->registers->sa = (uintptr_t)request->source_addr;
 -    channel->registers->da = (uintptr_t)request->dest_addr;
 -    channel->registers->sz = request->size;
 -    channel->registers->ctl = DMAIE | request->data_mode | request->addr_mode
 -      | request->transfer_mode | DMADT_4 | DMAEN | DMAREQ; /* repeated transfers */
 +    channel->registers->sa  = (uintptr_t)request->source_addr;
 +    channel->registers->da  = (uintptr_t)request->dest_addr;
 +    channel->registers->sz  = request->size;
 +    channel->registers->ctl = DMAIE | request->data_mode | request->addr_mode |
 +                              request->transfer_mode | DMADT_4 | DMAEN |
 +                              DMAREQ; /* repeated transfers */
      chSysUnlock();
 -}
 +  }
 -/**
 - * @brief   Releases exclusive control of a DMA channel.
 - * @details The channel is released from control and returned to the DMA engine
 - *          pool. Trying to release an unallocated channel is an illegal
 - *          operation and is trapped if assertions are enabled.
 - * @pre     The channel must have been acquired using @p dmaAcquire().
 - * @post    The channel is returned to the DMA engine pool.
 - */
 -void dmaRelease(msp430x_dma_ch_t * channel) {
 -  
 -  osalDbgCheck(channel != NULL);
 -  osalDbgAssert(channel->registers->ctl & DMADT_4, "not acquired");
 -  
 -  /* Release the channel in an idle mode */
 -  channel->registers->ctl = DMAABORT;
 -  
 -  /* release the DMA counter */
 +  /**
 +   * @brief   Releases exclusive control of a DMA channel.
 +   * @details The channel is released from control and returned to the DMA
 +   * engine
 +   *          pool. Trying to release an unallocated channel is an illegal
 +   *          operation and is trapped if assertions are enabled.
 +   * @pre     The channel must have been acquired using @p dmaAcquire().
 +   * @post    The channel is returned to the DMA engine pool.
 +   */
 +  void dmaRelease(msp430x_dma_ch_t * channel) {
 +
 +    osalDbgCheck(channel != NULL);
 +
 +    /* Release the channel in an idle mode */
 +    channel->registers->ctl = DMAABORT;
 +
 +/* release the DMA counter */
  #if CH_CFG_USE_SEMAPHORES
 -  chSemSignal(&dma_lock);
 +    chSemSignal(&dma_lock);
  #endif
 -}
 +  }
  #endif /* HAL_USE_DMA == TRUE */
 diff --git a/os/hal/ports/MSP430X/hal_dma_lld.h b/os/hal/ports/MSP430X/hal_dma_lld.h index 2cce85d..d1495d2 100644 --- a/os/hal/ports/MSP430X/hal_dma_lld.h +++ b/os/hal/ports/MSP430X/hal_dma_lld.h @@ -34,18 +34,18 @@  /*===========================================================================*/
  #define MSP430X_DMA_SINGLE DMADT_0
 -#define MSP430X_DMA_BLOCK  DMADT_1
 -#define MSP430X_DMA_BURST  DMADT_2
 +#define MSP430X_DMA_BLOCK DMADT_1
 +#define MSP430X_DMA_BURST DMADT_2
 -#define MSP430X_DMA_SRCINCR   DMASRCINCR_3
 -#define MSP430X_DMA_SRCDECR   DMASRCINCR_2
 -#define MSP430X_DMA_DSTINCR   DMADSTINCR_3
 -#define MSP430X_DMA_DSTDECR   DMADSTINCR_2
 +#define MSP430X_DMA_SRCINCR DMASRCINCR_3
 +#define MSP430X_DMA_SRCDECR DMASRCINCR_2
 +#define MSP430X_DMA_DSTINCR DMADSTINCR_3
 +#define MSP430X_DMA_DSTDECR DMADSTINCR_2
 -#define MSP430X_DMA_SRCBYTE   DMASRCBYTE
 -#define MSP430X_DMA_DSTBYTE   DMADSTBYTE
 -#define MSP430X_DMA_SRCWORD   0
 -#define MSP430X_DMA_DSTWORD   0
 +#define MSP430X_DMA_SRCBYTE DMASRCBYTE
 +#define MSP430X_DMA_DSTBYTE DMADSTBYTE
 +#define MSP430X_DMA_SRCWORD 0
 +#define MSP430X_DMA_DSTWORD 0
  /*===========================================================================*/
  /* Driver pre-compile time settings.                                         */
 @@ -56,8 +56,8 @@  /*===========================================================================*/
  #if !defined(DMA_BASE) && !defined(MSP430X_DMA_SOFTWARE)
 -  #error "The MSP430 device in use does not support DMA. Explicitly enable"
 -  #error "software support by defining MSP430X_DMA_SOFTWARE."
 +#error "The MSP430 device in use does not support DMA. Explicitly enable"
 +#error "software emulation by defining MSP430X_DMA_SOFTWARE."
  #endif
  #if defined(__MSP430_HAS_DMAX_1__) || defined(__MSP430X_HAS_DMA_1__)
 @@ -67,7 +67,7 @@  #elif defined(__MSP430_HAS_DMAX_6__) || defined(__MSP430X_HAS_DMA_6__)
  #define MSP430X_DMA_CHANNELS 6
  #else
 -  #error "Unexpected error - how many DMA channels does your MSP have?"
 +#error "Unexpected error - how many DMA channels does your MSP have?"
  #endif
  /*===========================================================================*/
 @@ -77,28 +77,28 @@  /**
   * @brief     Type of DMA callback function pointer.
   */
 -typedef void (*msp430x_dma_cbp_t)(void *args);
 +typedef void (*msp430x_dma_cbp_t)(void * args);
  /**
   * @brief     DMA callback, function and argument.
   */
  typedef struct {
 -  msp430x_dma_cbp_t   callback; /**< @brief Callback function pointer   */
 -  void *              args;     /**< @brief Callback function arguments */
 +  msp430x_dma_cbp_t callback; /**< @brief Callback function pointer   */
 +  void * args;                /**< @brief Callback function arguments */
  } msp430x_dma_cb_t;
  /**
   * @brief     MSP430X DMA request structure.
   */
  typedef struct {
 -  void *    source_addr;    /**< @brief Source address                       */
 -  void *    dest_addr;      /**< @brief Destination address                  */
 -  uint16_t  size;           /**< @brief Number of values to transfer         */
 -  uint16_t  addr_mode;      /**< @brief Address manipulation mode            */
 -  uint16_t  data_mode;      /**< @brief Data sizes (b2b, w2w, b2w, w2b)      */
 -  uint16_t  transfer_mode;  /**< @brief Transfer mode (single, block, burst) */
 -  uint16_t  trigger;        /**< @brief Triggering event (see datasheet)     */
 -  msp430x_dma_cb_t callback;/**< @brief Callback function and arguments      */
 +  const void * source_addr;  /**< @brief Source address                       */
 +  void * dest_addr;          /**< @brief Destination address                  */
 +  uint16_t size;             /**< @brief Number of values to transfer         */
 +  uint16_t addr_mode;        /**< @brief Address manipulation mode            */
 +  uint16_t data_mode;        /**< @brief Data sizes (b2b, w2w, b2w, w2b)      */
 +  uint16_t transfer_mode;    /**< @brief Transfer mode (single, block, burst) */
 +  uint16_t trigger;          /**< @brief Triggering event (see datasheet)     */
 +  msp430x_dma_cb_t callback; /**< @brief Callback function and arguments      */
  } msp430x_dma_req_t;
  /**
 @@ -133,7 +133,7 @@ typedef struct {   */
  typedef struct {
    msp430x_dma_ch_reg_t * registers; /**< @brief Pointer to channel registers */
 -  volatile uint8_t * ctl; /**< @brief Pointer to channel control register    */
 +  uint8_t index; /**< @brief Index of channel trigger control register    */
    msp430x_dma_cb_t * cb; /**< @brief Pointer to callback function  and args  */
  } msp430x_dma_ch_t;
 @@ -143,11 +143,11 @@ typedef struct {  /**
   * @brief     Identifies a DMA trigger using a mnemonic.
 - * 
 + *
   * @param[in] mnem    The mnemonic for the trigger, e.g. UCA0RXIFG to trigger
   *                    on UART receive.
   */
 -#define DMA_TRIGGER_MNEM(mnem) DMA0TSEL__ ## mnem
 +#define DMA_TRIGGER_MNEM(mnem) DMA0TSEL__##mnem
  /** @} */
 @@ -158,12 +158,12 @@ typedef struct {  #ifdef __cplusplus
  extern "C" {
  #endif
 -  void dmaInit(void);
 -  bool dmaRequest(msp430x_dma_req_t * request, systime_t timeout);
 -  bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index);
 -  void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request); 
 -  void dmaRelease(msp430x_dma_ch_t * channel);
 -  
 +void dmaInit(void);
 +bool dmaRequest(msp430x_dma_req_t * request, systime_t timeout);
 +bool dmaAcquire(msp430x_dma_ch_t * channel, uint8_t index);
 +void dmaTransfer(msp430x_dma_ch_t * channel, msp430x_dma_req_t * request);
 +void dmaRelease(msp430x_dma_ch_t * channel);
 +
  #ifdef __cplusplus
  }
  #endif
 @@ -171,4 +171,3 @@ extern "C" {  #endif /* HAL_USE_DMA == true */
  #endif /* HAL_MSP430X_DMA_H */
 -
 diff --git a/os/hal/ports/MSP430X/hal_pal_lld.h b/os/hal/ports/MSP430X/hal_pal_lld.h index 8789ed1..0b6363b 100644 --- a/os/hal/ports/MSP430X/hal_pal_lld.h +++ b/os/hal/ports/MSP430X/hal_pal_lld.h @@ -42,25 +42,25 @@  /**
   * @brief   Alternate mode 1
   */
 -#define PAL_MSP430X_ALTERNATE_1   8
 +#define PAL_MSP430X_ALTERNATE_1 8
  /**
   * @brief   Alternate mode 2
   */
 -#define PAL_MSP430X_ALTERNATE_2   9
 +#define PAL_MSP430X_ALTERNATE_2 9
  /**
   * @brief   Alternate mode 3
   */
 -#define PAL_MSP430X_ALTERNATE_3   10
 +#define PAL_MSP430X_ALTERNATE_3 10
 -#define ALTERNATE_HELP(n)   (PAL_MSP430X_ALTERNATE_ ## n)
 +#define ALTERNATE_HELP(n) (PAL_MSP430X_ALTERNATE_##n)
  /**
   * @brief   Alternate function.
 - * 
 + *
   * @param[in] n   alternate function selector - 1 through 3
   */
 -#define PAL_MODE_ALTERNATE(n)     (ALTERNATE_HELP(n))
 +#define PAL_MODE_ALTERNATE(n) (ALTERNATE_HELP(n))
  /** @} */
 @@ -75,17 +75,16 @@  /**
   * @brief   Width, in bits, of an I/O port.
   */
 -#define PAL_IOPORTS_WIDTH           16U
 +#define PAL_IOPORTS_WIDTH 16U
  /**
   * @brief   Whole port mask.
   * @details This macro specifies all the valid bits into a port.
   */
 -#define PAL_WHOLE_PORT              ((ioportmask_t)0xFFFFU)
 +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFU)
  /** @} */
 -
  /**
   * @name    Line handling macros
   * @{
 @@ -97,25 +96,24 @@   * @note    In this driver the pad number is encoded in the upper 4 bits of
   *          the GPIO address which are guaranteed to be zero.
   */
 -#define PAL_LINE(port, pad)                                                 \
 +#define PAL_LINE(port, pad)                                                    \
    ((ioline_t)((uint16_t)(port)) | (((uint16_t)(pad)) << 12))
  /**
   * @brief   Decodes a port identifier from a line identifier.
   */
 -#define PAL_PORT(line)                                                      \
 +#define PAL_PORT(line)                                                         \
    ((msp430x_gpio_registers_t *)(((uint16_t)(line)) & 0x0FFFU))
  /**
   * @brief   Decodes a pad identifier from a line identifier.
   */
 -#define PAL_PAD(line)                                                       \
 -  ((uint16_t)((uint16_t)(line) >> 12))
 +#define PAL_PAD(line) ((uint16_t)((uint16_t)(line) >> 12))
  /**
   * @brief   Value identifying an invalid line.
   */
 -#define PAL_NOLINE                      0U
 +#define PAL_NOLINE 0U
  /** @} */
  /**
 @@ -220,35 +218,35 @@ typedef msp430x_gpio_registers_t * ioportid_t;   * @brief   GPIO port A identifier.
   */
  #if defined(PA_BASE) || defined(__DOXYGEN__)
 -#define IOPORT1   ((volatile msp430x_gpio_registers_t *)PA_BASE)
 +#define IOPORT1 ((volatile msp430x_gpio_registers_t *)PA_BASE)
  #endif
  /**
   * @brief   GPIO port B identifier.
   */
  #if defined(PB_BASE) || defined(__DOXYGEN__)
 -#define IOPORT2   ((volatile msp430x_gpio_registers_t *)PB_BASE)
 +#define IOPORT2 ((volatile msp430x_gpio_registers_t *)PB_BASE)
  #endif
  /**
   * @brief   GPIO port C identifier.
   */
  #if defined(PC_BASE) || defined(__DOXYGEN__)
 -#define IOPORT3   ((volatile msp430x_gpio_registers_t *)PC_BASE)
 +#define IOPORT3 ((volatile msp430x_gpio_registers_t *)PC_BASE)
  #endif
  /**
   * @brief   GPIO port D identifier.
   */
  #if defined(PD_BASE) || defined(__DOXYGEN__)
 -#define IOPORT4   ((volatile msp430x_gpio_registers_t *)PD_BASE)
 +#define IOPORT4 ((volatile msp430x_gpio_registers_t *)PD_BASE)
  #endif
  /**
   * @brief   GPIO port E identifier.
   */
  #if defined(PE_BASE) || defined(__DOXYGEN__)
 -#define IOPORT5   ((volatile msp430x_gpio_registers_t *)PE_BASE)
 +#define IOPORT5 ((volatile msp430x_gpio_registers_t *)PE_BASE)
  #endif
  /**
 @@ -261,7 +259,7 @@ typedef msp430x_gpio_registers_t * ioportid_t;  /**
   * @brief   GPIO port J identifier.
   */
 -#define IOPORT0   ((volatile msp430x_gpio_registers_t *)PJ_BASE)
 +#define IOPORT0 ((volatile msp430x_gpio_registers_t *)PJ_BASE)
  /*===========================================================================*/
  /* Implementation, some of the following macros could be implemented as      */
 @@ -307,8 +305,7 @@ typedef msp430x_gpio_registers_t * ioportid_t;   *
   * @notapi
   */
 -#define pal_lld_writeport(port, bits) ((port)->out = (bits)) 
 -
 +#define pal_lld_writeport(port, bits) ((port)->out = (bits))
  /**
   * @brief   Sets a bits mask on a I/O port.
 @@ -353,7 +350,7 @@ typedef msp430x_gpio_registers_t * ioportid_t;   *
   * @notapi
   */
 -#define pal_lld_setgroupmode(port, mask, offset, mode)                      \
 +#define pal_lld_setgroupmode(port, mask, offset, mode)                         \
    _pal_lld_setgroupmode(port, mask << offset, mode)
  /**
 @@ -366,7 +363,7 @@ typedef msp430x_gpio_registers_t * ioportid_t;   *
   * @notapi
   */
 -#define pal_lld_clearpad(port, pad) ((port)->out &= ~(BIT ## pad))
 +#define pal_lld_clearpad(port, pad) ((port)->out &= ~(1 << pad))
  #if !defined(__DOXYGEN__)
  extern const PALConfig pal_default_config;
 @@ -375,10 +372,8 @@ extern const PALConfig pal_default_config;  #ifdef __cplusplus
  extern "C" {
  #endif
 -  void _pal_lld_init(const PALConfig *config);
 -  void _pal_lld_setgroupmode(ioportid_t port,
 -                             ioportmask_t mask,
 -                             iomode_t mode);
 +void _pal_lld_init(const PALConfig * config);
 +void _pal_lld_setgroupmode(ioportid_t port, ioportmask_t mask, iomode_t mode);
  #ifdef __cplusplus
  }
  #endif
 diff --git a/os/hal/ports/MSP430X/hal_serial_lld.c b/os/hal/ports/MSP430X/hal_serial_lld.c index bc002cb..0d9aa1c 100644 --- a/os/hal/ports/MSP430X/hal_serial_lld.c +++ b/os/hal/ports/MSP430X/hal_serial_lld.c @@ -37,33 +37,49 @@  /** @brief USART0 serial driver identifier.*/
  #if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__)
  #ifndef __MSP430_HAS_EUSCI_A0__
 -  #error "Cannot find USCI module to use for SD0"
 +#error "Cannot find USCI module to use for SD0"
 +#endif
 +#ifdef MSP430X_USCI_A0_USED
 +#error "USCI module A0 already in use - USART0 not available"
  #endif
  SerialDriver SD0;
 +#define MSP430X_USCI_A0_USED
  #endif
  /** @brief USART1 serial driver identifier.*/
  #if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__)
  #ifndef __MSP430_HAS_EUSCI_A1__
 -  #error "Cannot find USCI module to use for SD1"
 +#error "Cannot find USCI module to use for SD1"
 +#endif
 +#ifdef MSP430X_USCI_A1_USED
 +#error "USCI module A1 already in use - USART1 not available"
  #endif
  SerialDriver SD1;
 +#define MSP430X_USCI_A1_USED
  #endif
  /** @brief USART2 serial driver identifier.*/
  #if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__)
  #ifndef __MSP430_HAS_EUSCI_A2__
 -  #error "Cannot find USCI module to use for SD2"
 +#error "Cannot find USCI module to use for SD2"
 +#endif
 +#ifdef MSP430X_USCI_A2_USED
 +#error "USCI module A2 already in use - USART2 not available"
  #endif
  SerialDriver SD2;
 +#define MSP430X_USCI_A2_USED
  #endif
  /** @brief USART3 serial driver identifier.*/
  #if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__)
  #ifndef __MSP430_HAS_EUSCI_A3__
 -  #error "Cannot find USCI module to use for SD3"
 +#error "Cannot find USCI module to use for SD3"
 +#endif
 +#ifdef MSP430X_USCI_A3_USED
 +#error "USCI module A3 already in use - USART3 not available"
  #endif
  SerialDriver SD3;
 +#define MSP430X_USCI_A3_USED
  #endif
  /*===========================================================================*/
 @@ -73,9 +89,7 @@ SerialDriver SD3;  /**
   * @brief   Driver default configuration.
   */
 -static const SerialConfig default_config = {
 -  SERIAL_DEFAULT_BITRATE
 -};
 +static const SerialConfig default_config = { SERIAL_DEFAULT_BITRATE };
  /*===========================================================================*/
  /* Driver local functions.                                                   */
 @@ -85,7 +99,7 @@ static const SerialConfig default_config = {   * @brief     UCBRS calculation.
   * @details   This function calculates the UCBRS value for oversampled baud
   *            rates.
 - *            
 + *
   * @param[in] frac    Fractional part of baud rate division, times 10000.
   */
  static uint8_t UCBRS(uint16_t frac) {
 @@ -160,7 +174,7 @@ static uint8_t UCBRS(uint16_t frac) {      return 0xFB;
    else if (frac < 9288)
      return 0xFD;
 -  else 
 +  else
      return 0xFE;
  }
 @@ -168,13 +182,13 @@ static uint8_t UCBRS(uint16_t frac) {   * @brief     Modulation control word calculator.
   * @details   This function calculates the modulation control word from the
   *            input clock frequency and the requested baud rate.
 - * 
 + *
   * @param[in] baud    Requested baud rate
   * @param[in] freq    Frequency of the clock driving the USCI module
   */
  static uint16_t UCAxMCTLW(uint32_t baud, uint32_t freq) {
 -  
 -  uint16_t n = freq/baud;
 +
 +  uint16_t n = freq / baud;
    /*uint16_t frac = (freq * 10000 / baud) - ((freq / baud) * 10000);*/
    uint16_t frac = (freq - (n * baud)) * 10000 / baud;
    if (n > 16) {
 @@ -190,12 +204,12 @@ static uint16_t UCAxMCTLW(uint32_t baud, uint32_t freq) {   * @brief     UCBRW calculation.
   * @details   This function calculates the UCBRW value for all baud
   *            rates.
 - *            
 + *
   * @param[in] baud    Requested baud rate
   * @param[in] freq    Frequency of the clock driving the USCI module
   */
  static uint16_t UCAxBRW(uint32_t baud, uint32_t freq) {
 -  uint16_t n = freq/baud;
 +  uint16_t n = freq / baud;
    if (n > 16) {
      return n >> 4;
    }
 @@ -203,88 +217,88 @@ static uint16_t UCAxBRW(uint32_t baud, uint32_t freq) {  }
  #if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__)
 -static void usart0_init(const SerialConfig *config) {
 -  UCA0BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ);
 +static void usart0_init(const SerialConfig * config) {
 +  UCA0BRW   = UCAxBRW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ);
    UCA0MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ);
    UCA0STATW = 0;
    UCA0ABCTL = 0;
    UCA0IRCTL = 0;
 -  UCA0CTLW0 = (MSP430X_USART0_PARITY << 14) | (MSP430X_USART0_ORDER << 13) | \
 -              (MSP430X_USART0_SIZE << 12) | (MSP430X_USART0_STOP << 11) | \
 +  UCA0CTLW0 = (MSP430X_USART0_PARITY << 14) | (MSP430X_USART0_ORDER << 13) |
 +              (MSP430X_USART0_SIZE << 12) | (MSP430X_USART0_STOP << 11) |
                (MSP430X_USART0_UCSSEL);
    UCA0IE = UCRXIE;
  }
  #endif
  #if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__)
 -static void usart1_init(const SerialConfig *config) {
 -  UCA1BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ);
 +static void usart1_init(const SerialConfig * config) {
 +  UCA1BRW   = UCAxBRW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ);
    UCA1MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ);
    UCA1STATW = 0;
    UCA1ABCTL = 0;
    UCA1IRCTL = 0;
 -  UCA1CTLW0 = (MSP430X_USART1_PARITY << 14) | (MSP430X_USART1_ORDER << 13) | \
 -              (MSP430X_USART1_SIZE << 12) | (MSP430X_USART1_STOP << 11) | \
 +  UCA1CTLW0 = (MSP430X_USART1_PARITY << 14) | (MSP430X_USART1_ORDER << 13) |
 +              (MSP430X_USART1_SIZE << 12) | (MSP430X_USART1_STOP << 11) |
                (MSP430X_USART1_UCSSEL);
    UCA1IE = UCRXIE;
  }
  #endif
  #if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__)
 -static void usart2_init(const SerialConfig *config) {
 -  UCA2BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART2_CLK_FREQ);
 +static void usart2_init(const SerialConfig * config) {
 +  UCA2BRW   = UCAxBRW(config->sc_bitrate, MSP430X_USART2_CLK_FREQ);
    UCA2MCTLW = UCAxMCTLW(config->sc_bitrate);
    UCA2STATW = 0;
    UCA2ABCTL = 0;
    UCA2IRCTL = 0;
 -  UCA2CTLW0 = (MSP430X_USART2_PARITY << 14) | (MSP430X_USART2_ORDER << 13) | \
 -              (MSP430X_USART2_SIZE << 12) | (MSP430X_USART2_STOP << 11) | \
 +  UCA2CTLW0 = (MSP430X_USART2_PARITY << 14) | (MSP430X_USART2_ORDER << 13) |
 +              (MSP430X_USART2_SIZE << 12) | (MSP430X_USART2_STOP << 11) |
                (MSP430X_USART2_UCSSEL);
    UCA2IE = UCRXIE;
  }
  #endif
  #if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__)
 -static void usart3_init(const SerialConfig *config) {
 -  UCA3BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ);
 +static void usart3_init(const SerialConfig * config) {
 +  UCA3BRW   = UCAxBRW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ);
    UCA3MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ);
    UCA3STATW = 0;
    UCA3ABCTL = 0;
    UCA3IRCTL = 0;
 -  UCA3CTLW0 = (MSP430X_USART3_PARITY << 14) | (MSP430X_USART3_ORDER << 13) | \
 -              (MSP430X_USART3_SIZE << 12) | (MSP430X_USART3_STOP << 11) | \
 +  UCA3CTLW0 = (MSP430X_USART3_PARITY << 14) | (MSP430X_USART3_ORDER << 13) |
 +              (MSP430X_USART3_SIZE << 12) | (MSP430X_USART3_STOP << 11) |
                (MSP430X_USART3_UCSSEL);
    UCA3IE = UCRXIE;
  }
  #endif
  #if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__)
 -static void notify0(io_queue_t *qp) {
 -  
 +static void notify0(io_queue_t * qp) {
 +
    (void)qp;
    UCA0IE |= UCTXIE;
  }
  #endif
  #if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__)
 -static void notify1(io_queue_t *qp) {
 -  
 +static void notify1(io_queue_t * qp) {
 +
    (void)qp;
    UCA1IE |= UCTXIE;
  }
  #endif
  #if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__)
 -static void notify2(io_queue_t *qp) {
 -  
 +static void notify2(io_queue_t * qp) {
 +
    (void)qp;
    UCA2IE |= UCTXIE;
  }
  #endif
  #if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__)
 -static void notify3(io_queue_t *qp) {
 -  
 +static void notify3(io_queue_t * qp) {
 +
    (void)qp;
    UCA3IE |= UCTXIE;
  }
 @@ -292,24 +306,23 @@ static void notify3(io_queue_t *qp) {  /**
   * @brief     Error handling routine.
 - * 
 + *
   * @param[in] sra     USCI status register containing errors
   * @param[in] sdp     pointer to a @p SerialDriver object
   */
 -static void set_error(uint16_t sra, SerialDriver *sdp) {
 -    eventflags_t sts = 0;
 -    
 -    if (sra & UCOE) 
 -      sts |= SD_OVERRUN_ERROR;
 -    if (sra & UCPE)
 -      sts |= SD_PARITY_ERROR;
 -    if (sra & UCFE)
 -      sts |= SD_FRAMING_ERROR;
 -    osalSysLockFromISR();
 -    chnAddFlagsI(sdp, sts);
 -    osalSysUnlockFromISR();
 +static void set_error(uint16_t sra, SerialDriver * sdp) {
 +  eventflags_t sts = 0;
 +
 +  if (sra & UCOE)
 +    sts |= SD_OVERRUN_ERROR;
 +  if (sra & UCPE)
 +    sts |= SD_PARITY_ERROR;
 +  if (sra & UCFE)
 +    sts |= SD_FRAMING_ERROR;
 +  osalSysLockFromISR();
 +  chnAddFlagsI(sdp, sts);
 +  osalSysUnlockFromISR();
  }
 -  
  /*===========================================================================*/
  /* Driver interrupt handlers.                                                */
 @@ -318,236 +331,235 @@ static void set_error(uint16_t sra, SerialDriver *sdp) {  #if MSP430X_SERIAL_USE_USART0 || defined(__DOXYGEN__)
  /**
   * @brief   USART0 interrupt handler.
 - * 
 + *
   * @isr
   */
  PORT_IRQ_HANDLER(USCI_A0_VECTOR) {
    msg_t b;
 -  
 +
    OSAL_IRQ_PROLOGUE();
 -  
 -  switch (__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG)) {
 -    case USCI_UART_UCRXIFG: /* RX interrupt */
 -      
 -      /* Detect errors */
 -      if (UCA0STATW & UCRXERR)
 -        set_error(UCA0STATW, &SD0);
 -      
 -      /* Data available */
 -      osalSysLockFromISR();
 -      sdIncomingDataI(&SD0, UCA0RXBUF);
 -      osalSysUnlockFromISR();
 -      break;
 -      
 -    case USCI_UART_UCTXIFG: /* TX interrupt */
 -      
 -      /* Transmission buffer empty */
 -      osalSysLockFromISR();
 -      b = sdRequestDataI(&SD0);
 -      if (b < Q_OK) {
 -        chnAddFlagsI(&SD0, CHN_OUTPUT_EMPTY);
 -        UCA0IE = (UCA0IE & ~UCTXIE) | UCTXCPTIE;
 -        UCA0IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
 -      }
 -      else
 -        UCA0TXBUF = b;
 -      osalSysUnlockFromISR();
 -      break;
 -      
 -    case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
 -      
 -      /* Physical transmission end */
 -      osalSysLockFromISR();
 -      if (oqIsEmptyI(&SD0.oqueue))
 -        chnAddFlagsI(&SD0, CHN_TRANSMISSION_END);
 -      UCA0IE &= ~UCTXCPTIE;
 -      break;
 -      
 -    default: /* other interrupts */
 -      while (1);
 -      break;
 +
 +  switch (__even_in_range(UCA0IV, USCI_UART_UCTXCPTIFG)) {
 +  case USCI_UART_UCRXIFG: /* RX interrupt */
 +
 +    /* Detect errors */
 +    if (UCA0STATW & UCRXERR)
 +      set_error(UCA0STATW, &SD0);
 +
 +    /* Data available */
 +    osalSysLockFromISR();
 +    sdIncomingDataI(&SD0, UCA0RXBUF);
 +    osalSysUnlockFromISR();
 +    break;
 +
 +  case USCI_UART_UCTXIFG: /* TX interrupt */
 +
 +    /* Transmission buffer empty */
 +    osalSysLockFromISR();
 +    b = sdRequestDataI(&SD0);
 +    if (b < Q_OK) {
 +      chnAddFlagsI(&SD0, CHN_OUTPUT_EMPTY);
 +      UCA0IE = (UCA0IE & ~UCTXIE) | UCTXCPTIE;
 +      UCA0IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
 +    }
 +    else
 +      UCA0TXBUF = b;
 +    osalSysUnlockFromISR();
 +    break;
 +
 +  case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
 +
 +    /* Physical transmission end */
 +    osalSysLockFromISR();
 +    if (oqIsEmptyI(&SD0.oqueue))
 +      chnAddFlagsI(&SD0, CHN_TRANSMISSION_END);
 +    UCA0IE &= ~UCTXCPTIE;
 +    break;
 +
 +  default: /* other interrupts */
 +    while (1)
 +      ;
 +    break;
    }
 -  
 +
    OSAL_IRQ_EPILOGUE();
 -  
  }
  #endif
  #if MSP430X_SERIAL_USE_USART1 || defined(__DOXYGEN__)
  /**
   * @brief   USART1 interrupt handler.
 - * 
 + *
   * @isr
   */
  PORT_IRQ_HANDLER(USCI_A1_VECTOR) {
    msg_t b;
 -  
 +
    OSAL_IRQ_PROLOGUE();
 -  
 -  switch (__even_in_range(UCA1IV,USCI_UART_UCTXCPTIFG)) {
 -    case USCI_UART_UCRXIFG: /* RX interrupt */
 -      
 -      /* Detect errors */
 -      if (UCA1STATW & UCRXERR)
 -        set_error(UCA1STATW, &SD1);
 -      
 -      /* Data available */
 -      osalSysLockFromISR();
 -      sdIncomingDataI(&SD1, UCA1RXBUF);
 -      osalSysUnlockFromISR();
 -      break;
 -      
 -    case USCI_UART_UCTXIFG: /* TX interrupt */
 -      
 -      /* Transmission buffer empty */
 -      osalSysLockFromISR();
 -      b = sdRequestDataI(&SD1);
 -      if (b < Q_OK) {
 -        chnAddFlagsI(&SD1, CHN_OUTPUT_EMPTY);
 -        UCA1IE = (UCA1IE & ~UCTXIE) | UCTXCPTIE;
 -        UCA1IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
 -      }
 -      else
 -        UCA1TXBUF = b;
 -      osalSysUnlockFromISR();
 -      break;
 -      
 -    case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
 -      
 -      /* Physical transmission end */
 -      osalSysLockFromISR();
 -      if (oqIsEmptyI(&SD1.oqueue))
 -        chnAddFlagsI(&SD1, CHN_TRANSMISSION_END);
 -      UCA1IE &= ~UCTXCPTIE;
 -      break;
 -      
 -    default: /* other interrupts */
 -      while (1);
 -      break;
 +
 +  switch (__even_in_range(UCA1IV, USCI_UART_UCTXCPTIFG)) {
 +  case USCI_UART_UCRXIFG: /* RX interrupt */
 +
 +    /* Detect errors */
 +    if (UCA1STATW & UCRXERR)
 +      set_error(UCA1STATW, &SD1);
 +
 +    /* Data available */
 +    osalSysLockFromISR();
 +    sdIncomingDataI(&SD1, UCA1RXBUF);
 +    osalSysUnlockFromISR();
 +    break;
 +
 +  case USCI_UART_UCTXIFG: /* TX interrupt */
 +
 +    /* Transmission buffer empty */
 +    osalSysLockFromISR();
 +    b = sdRequestDataI(&SD1);
 +    if (b < Q_OK) {
 +      chnAddFlagsI(&SD1, CHN_OUTPUT_EMPTY);
 +      UCA1IE = (UCA1IE & ~UCTXIE) | UCTXCPTIE;
 +      UCA1IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
 +    }
 +    else
 +      UCA1TXBUF = b;
 +    osalSysUnlockFromISR();
 +    break;
 +
 +  case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
 +
 +    /* Physical transmission end */
 +    osalSysLockFromISR();
 +    if (oqIsEmptyI(&SD1.oqueue))
 +      chnAddFlagsI(&SD1, CHN_TRANSMISSION_END);
 +    UCA1IE &= ~UCTXCPTIE;
 +    break;
 +
 +  default: /* other interrupts */
 +    while (1)
 +      ;
 +    break;
    }
 -  
 +
    OSAL_IRQ_EPILOGUE();
 -  
  }
  #endif
  #if MSP430X_SERIAL_USE_USART2 || defined(__DOXYGEN__)
  /**
   * @brief   USART2 interrupt handler.
 - * 
 + *
   * @isr
   */
  PORT_IRQ_HANDLER(USCI_A2_VECTOR) {
    msg_t b;
 -  
 +
    OSAL_IRQ_PROLOGUE();
 -  
 -  switch (__even_in_range(UCA2IV,USCI_UART_UCTXCPTIFG)) {
 -    case USCI_UART_UCRXIFG: /* RX interrupt */
 -      
 -      /* Detect errors */
 -      if (UCA2STATW & UCRXERR)
 -        set_error(UCA2STATW, &SD2);
 -      
 -      /* Data available */
 -      osalSysLockFromISR();
 -      sdIncomingDataI(&SD2, UCA2RXBUF);
 -      osalSysUnlockFromISR();
 -      break;
 -      
 -    case USCI_UART_UCTXIFG: /* TX interrupt */
 -      
 -      /* Transmission buffer empty */
 -      osalSysLockFromISR();
 -      b = sdRequestDataI(&SD2);
 -      if (b < Q_OK) {
 -        chnAddFlagsI(&SD2, CHN_OUTPUT_EMPTY);
 -        UCA2IE = (UCA2IE & ~UCTXIE) | UCTXCPTIE;
 -        UCA2IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
 -      }
 -      else
 -        UCA2TXBUF = b;
 -      osalSysUnlockFromISR();
 -      break;
 -      
 -    case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
 -      
 -      /* Physical transmission end */
 -      osalSysLockFromISR();
 -      if (oqIsEmptyI(&SD2.oqueue))
 -        chnAddFlagsI(&SD2, CHN_TRANSMISSION_END);
 -      UCA2IE &= ~UCTXCPTIE;
 -      break;
 -      
 -    default: /* other interrupts */
 -      while (1);
 -      break;
 +
 +  switch (__even_in_range(UCA2IV, USCI_UART_UCTXCPTIFG)) {
 +  case USCI_UART_UCRXIFG: /* RX interrupt */
 +
 +    /* Detect errors */
 +    if (UCA2STATW & UCRXERR)
 +      set_error(UCA2STATW, &SD2);
 +
 +    /* Data available */
 +    osalSysLockFromISR();
 +    sdIncomingDataI(&SD2, UCA2RXBUF);
 +    osalSysUnlockFromISR();
 +    break;
 +
 +  case USCI_UART_UCTXIFG: /* TX interrupt */
 +
 +    /* Transmission buffer empty */
 +    osalSysLockFromISR();
 +    b = sdRequestDataI(&SD2);
 +    if (b < Q_OK) {
 +      chnAddFlagsI(&SD2, CHN_OUTPUT_EMPTY);
 +      UCA2IE = (UCA2IE & ~UCTXIE) | UCTXCPTIE;
 +      UCA2IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
 +    }
 +    else
 +      UCA2TXBUF = b;
 +    osalSysUnlockFromISR();
 +    break;
 +
 +  case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
 +
 +    /* Physical transmission end */
 +    osalSysLockFromISR();
 +    if (oqIsEmptyI(&SD2.oqueue))
 +      chnAddFlagsI(&SD2, CHN_TRANSMISSION_END);
 +    UCA2IE &= ~UCTXCPTIE;
 +    break;
 +
 +  default: /* other interrupts */
 +    while (1)
 +      ;
 +    break;
    }
 -  
 +
    OSAL_IRQ_EPILOGUE();
 -  
  }
  #endif
  #if MSP430X_SERIAL_USE_USART3 || defined(__DOXYGEN__)
  /**
   * @brief   USART3 interrupt handler.
 - * 
 + *
   * @isr
   */
  PORT_IRQ_HANDLER(USCI_A3_VECTOR) {
    msg_t b;
 -  
 +
    OSAL_IRQ_PROLOGUE();
 -  
 -  switch (__even_in_range(UCA3IV,USCI_UART_UCTXCPTIFG)) {
 -    case USCI_UART_UCRXIFG: /* RX interrupt */
 -      
 -      /* Detect errors */
 -      if (UCA3STATW & UCRXERR)
 -        set_error(UCA3STATW, &SD3);
 -      
 -      /* Data available */
 -      osalSysLockFromISR();
 -      sdIncomingDataI(&SD3, UCA3RXBUF);
 -      osalSysUnlockFromISR();
 -      break;
 -      
 -    case USCI_UART_UCTXIFG: /* TX interrupt */
 -      
 -      /* Transmission buffer empty */
 -      osalSysLockFromISR();
 -      b = sdRequestDataI(&SD3);
 -      if (b < Q_OK) {
 -        chnAddFlagsI(&SD3, CHN_OUTPUT_EMPTY);
 -        UCA3IE = (UCA3IE & ~UCTXIE) | UCTXCPTIE;
 -        UCA3IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
 -      }
 -      else
 -        UCA3TXBUF = b;
 -      osalSysUnlockFromISR();
 -      break;
 -      
 -    case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
 -      
 -      /* Physical transmission end */
 -      osalSysLockFromISR();
 -      if (oqIsEmptyI(&SD3.oqueue))
 -        chnAddFlagsI(&SD3, CHN_TRANSMISSION_END);
 -      UCA3IE &= ~UCTXCPTIE;
 -      break;
 -      
 -    default: /* other interrupts */
 -      while (1);
 -      break;
 +
 +  switch (__even_in_range(UCA3IV, USCI_UART_UCTXCPTIFG)) {
 +  case USCI_UART_UCRXIFG: /* RX interrupt */
 +
 +    /* Detect errors */
 +    if (UCA3STATW & UCRXERR)
 +      set_error(UCA3STATW, &SD3);
 +
 +    /* Data available */
 +    osalSysLockFromISR();
 +    sdIncomingDataI(&SD3, UCA3RXBUF);
 +    osalSysUnlockFromISR();
 +    break;
 +
 +  case USCI_UART_UCTXIFG: /* TX interrupt */
 +
 +    /* Transmission buffer empty */
 +    osalSysLockFromISR();
 +    b = sdRequestDataI(&SD3);
 +    if (b < Q_OK) {
 +      chnAddFlagsI(&SD3, CHN_OUTPUT_EMPTY);
 +      UCA3IE = (UCA3IE & ~UCTXIE) | UCTXCPTIE;
 +      UCA3IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */
 +    }
 +    else
 +      UCA3TXBUF = b;
 +    osalSysUnlockFromISR();
 +    break;
 +
 +  case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */
 +
 +    /* Physical transmission end */
 +    osalSysLockFromISR();
 +    if (oqIsEmptyI(&SD3.oqueue))
 +      chnAddFlagsI(&SD3, CHN_TRANSMISSION_END);
 +    UCA3IE &= ~UCTXCPTIE;
 +    break;
 +
 +  default: /* other interrupts */
 +    while (1)
 +      ;
 +    break;
    }
 -  
 +
    OSAL_IRQ_EPILOGUE();
 -  
  }
  #endif
 -
  /*===========================================================================*/
  /* Driver exported functions.                                                */
  /*===========================================================================*/
 @@ -586,13 +598,12 @@ void sd_lld_init(void) {   *
   * @notapi
   */
 -void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
 +void sd_lld_start(SerialDriver * sdp, const SerialConfig * config) {
    if (config == NULL) {
      config = &default_config;
    }
 -
    if (sdp->state == SD_STOP) {
  #if MSP430X_SERIAL_USE_USART0 == TRUE
      if (&SD0 == sdp) {
 @@ -626,7 +637,7 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {   *
   * @notapi
   */
 -void sd_lld_stop(SerialDriver *sdp) {
 +void sd_lld_stop(SerialDriver * sdp) {
    if (sdp->state == SD_READY) {
  #if MSP430X_SERIAL_USE_USART0 == TRUE
 diff --git a/os/hal/ports/MSP430X/hal_spi_lld.c b/os/hal/ports/MSP430X/hal_spi_lld.c new file mode 100644 index 0000000..70a357e --- /dev/null +++ b/os/hal/ports/MSP430X/hal_spi_lld.c @@ -0,0 +1,578 @@ +/*
 +    ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle
 +
 +    Licensed under the Apache License, Version 2.0 (the "License");
 +    you may not use this file except in compliance with the License.
 +    You may obtain a copy of the License at
 +
 +        http://www.apache.org/licenses/LICENSE-2.0
 +
 +    Unless required by applicable law or agreed to in writing, software
 +    distributed under the License is distributed on an "AS IS" BASIS,
 +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 +    See the License for the specific language governing permissions and
 +    limitations under the License.
 +*/
 +
 +/**
 + * @file    hal_spi_lld.c
 + * @brief   MSP430X SPI subsystem low level driver source.
 + *
 + * @addtogroup SPI
 + * @{
 + */
 +
 +#include "hal.h"
 +
 +#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
 +
 +/*===========================================================================*/
 +/* Driver local definitions.                                                 */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Driver exported variables.                                                */
 +/*===========================================================================*/
 +
 +/**
 + * @brief   SPIA0 driver identifier.
 + */
 +#if (MSP430X_SPI_USE_SPIA0 == TRUE) || defined(__DOXYGEN__)
 +SPIDriver SPIDA0;
 +#endif
 +
 +/**
 + * @brief   SPIA1 driver identifier.
 + */
 +#if (MSP430X_SPI_USE_SPIA1 == TRUE) || defined(__DOXYGEN__)
 +SPIDriver SPIDA1;
 +#endif
 +
 +/**
 + * @brief   SPIA2 driver identifier.
 + */
 +#if (MSP430X_SPI_USE_SPIA2 == TRUE) || defined(__DOXYGEN__)
 +SPIDriver SPIDA2;
 +#endif
 +
 +/**
 + * @brief   SPIA3 driver identifier.
 + */
 +#if (MSP430X_SPI_USE_SPIA3 == TRUE) || defined(__DOXYGEN__)
 +SPIDriver SPIDA3;
 +#endif
 +
 +/**
 + * @brief   SPIB0 driver identifier.
 + */
 +#if (MSP430X_SPI_USE_SPIB0 == TRUE) || defined(__DOXYGEN__)
 +SPIDriver SPIDB0;
 +#endif
 +
 +/**
 + * @brief   SPIB1 driver identifier.
 + */
 +#if (MSP430X_SPI_USE_SPIB1 == TRUE) || defined(__DOXYGEN__)
 +SPIDriver SPIDB1;
 +#endif
 +
 +/**
 + * @brief   SPIB2 driver identifier.
 + */
 +#if (MSP430X_SPI_USE_SPIB2 == TRUE) || defined(__DOXYGEN__)
 +SPIDriver SPIDB2;
 +#endif
 +
 +/**
 + * @brief   SPIB3 driver identifier.
 + */
 +#if (MSP430X_SPI_USE_SPIB3 == TRUE) || defined(__DOXYGEN__)
 +SPIDriver SPIDB3;
 +#endif
 +
 +/*===========================================================================*/
 +/* Driver local variables and types.                                         */
 +/*===========================================================================*/
 +
 +static const uint16_t dummytx = 0xFFFFU;
 +static uint16_t dummyrx;
 +
 +/*===========================================================================*/
 +/* Driver local functions.                                                   */
 +/*===========================================================================*/
 +
 +static void init_transfer(SPIDriver * spip) {
 +
 +#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE || defined(__DOXYGEN__)
 +  if (spip->config->dmarx_index > MSP430X_DMA_CHANNELS) {
 +    dmaRequest(&(spip->rx_req), TIME_INFINITE);
 +  }
 +  else {
 +    dmaTransfer(&(spip->dmarx), &(spip->rx_req));
 +  }
 +  if (spip->config->dmatx_index > MSP430X_DMA_CHANNELS) {
 +    dmaRequest(&(spip->tx_req), TIME_INFINITE);
 +  }
 +  else {
 +    dmaTransfer(&(spip->dmatx), &(spip->tx_req));
 +  }
 +#else
 +  dmaRequest(&(spip->rx_req), TIME_INFINITE);
 +  dmaRequest(&(spip->tx_req), TIME_INFINITE);
 +#endif
 +
 +  *(spip->ifg) |= UCTXIFG;
 +}
 +
 +/**
 + * @brief   Shared end-of-transfer callback.
 + *
 + * @param[in] spip    pointer to the @p SPIDriver object
 + * @note    This function is called in ISR context by the DMA code.
 + */
 +static void spi_lld_end_of_transfer(void * spip) {
 +
 +  /* So that future transfers will actually work */
 +  *(((SPIDriver *)spip)->ifg) &= ~(UCTXIFG);
 +  /* NOTE to future me - this macro sets the driver state and calls the
 +   * configured callback end_cb, if applicable. That callback doesn't seem to
 +   * be modifiable without reconfiguring the whole driver. */
 +  _spi_isr_code((SPIDriver *)spip);
 +}
 +/*===========================================================================*/
 +/* Driver interrupt handlers.                                                */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Driver exported functions.                                                */
 +/*===========================================================================*/
 +
 +/**
 + * @brief   Low level SPI driver initialization.
 + *
 + * @notapi
 + */
 +void spi_lld_init(void) {
 +
 +#if MSP430X_SPI_USE_SPIA0 == TRUE
 +  /* Driver initialization.*/
 +  spiObjectInit(&SPIDA0);
 +  SPIDA0.regs                     = (msp430x_spi_reg_t *)(&UCA0CTLW0);
 +  SPIDA0.ifg                      = (volatile uint16_t *)&UCA0IFG;
 +  SPIDA0.tx_req.trigger           = DMA_TRIGGER_MNEM(UCA0TXIFG);
 +  SPIDA0.rx_req.trigger           = DMA_TRIGGER_MNEM(UCA0RXIFG);
 +  SPIDA0.tx_req.dest_addr         = &(SPIDA0.regs->txbuf);
 +  SPIDA0.rx_req.source_addr       = &(SPIDA0.regs->rxbuf);
 +  SPIDA0.tx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDA0.rx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDA0.tx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDA0.rx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDA0.tx_req.callback.callback = NULL;
 +  SPIDA0.tx_req.callback.args     = NULL;
 +  SPIDA0.rx_req.callback.callback = spi_lld_end_of_transfer;
 +  SPIDA0.rx_req.callback.args     = &SPIDA0;
 +/* NOTE to my future self - this must be SINGLE because BLOCK and BURST
 + * don't wait for triggers and would overflow both buffers. Don't worry, it
 + * still works - the transfer isn't complete until SZ bytes are transferred */
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA1 == TRUE
 +  /* Driver initialization.*/
 +  spiObjectInit(&SPIDA1);
 +  SPIDA1.regs                     = (msp430x_spi_reg_t *)(&UCA1CTLW0);
 +  SPIDA1.ifg                      = (volatile uint16_t *)&UCA1IFG;
 +  SPIDA1.tx_req.trigger           = DMA_TRIGGER_MNEM(UCA1TXIFG);
 +  SPIDA1.rx_req.trigger           = DMA_TRIGGER_MNEM(UCA1RXIFG);
 +  SPIDA1.tx_req.dest_addr         = &(SPIDA1.regs->txbuf);
 +  SPIDA1.rx_req.source_addr       = &(SPIDA1.regs->rxbuf);
 +  SPIDA1.tx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDA1.rx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDA1.tx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDA1.rx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDA1.tx_req.callback.callback = NULL;
 +  SPIDA1.tx_req.callback.args     = NULL;
 +  SPIDA1.rx_req.callback.callback = spi_lld_end_of_transfer;
 +  SPIDA1.rx_req.callback.args     = &SPIDA1;
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA2 == TRUE
 +  /* Driver initialization.*/
 +  spiObjectInit(&SPIDA2);
 +  SPIDA2.regs                     = (msp430x_spi_reg_t *)(&UCA2CTLW0);
 +  SPIDA2.ifg                      = (volatile uint16_t *)&UCA2IFG;
 +  SPIDA2.tx_req.trigger           = DMA_TRIGGER_MNEM(UCA2TXIFG);
 +  SPIDA2.rx_req.trigger           = DMA_TRIGGER_MNEM(UCA2RXIFG);
 +  SPIDA2.tx_req.dest_addr         = &(SPIDA2.regs->txbuf);
 +  SPIDA2.rx_req.source_addr       = &(SPIDA2.regs->rxbuf);
 +  SPIDA2.tx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDA2.rx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDA2.tx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDA2.rx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDA2.tx_req.callback.callback = NULL;
 +  SPIDA2.tx_req.callback.args     = NULL;
 +  SPIDA2.rx_req.callback.callback = spi_lld_end_of_transfer;
 +  SPIDA2.rx_req.callback.args     = &SPIDA2;
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA3 == TRUE
 +  /* Driver initialization.*/
 +  spiObjectInit(&SPIDA3);
 +  SPIDA3.regs                     = (msp430x_spi_reg_t *)(&UCA3CTLW0);
 +  SPIDA3.ifg                      = (volatile uint16_t *)&UCA3IFG;
 +  SPIDA3.tx_req.trigger           = DMA_TRIGGER_MNEM(UCA3TXIFG);
 +  SPIDA3.rx_req.trigger           = DMA_TRIGGER_MNEM(UCA3RXIFG);
 +  SPIDA3.tx_req.dest_addr         = &(SPIDA3.regs->txbuf);
 +  SPIDA3.rx_req.source_addr       = &(SPIDA3.regs->rxbuf);
 +  SPIDA3.tx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDA3.rx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDA3.tx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDA3.rx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDA3.tx_req.callback.callback = NULL;
 +  SPIDA3.tx_req.callback.args     = NULL;
 +  SPIDA3.rx_req.callback.callback = spi_lld_end_of_transfer;
 +  SPIDA3.rx_req.callback.args     = &SPIDA3;
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB0 == TRUE
 +  /* Driver initialization.*/
 +  spiObjectInit(&SPIDB0);
 +  SPIDB0.regs                     = (msp430x_spi_reg_t *)(&UCB0CTLW0);
 +  SPIDB0.ifg                      = (volatile uint16_t *)&UCB0IFG;
 +  SPIDB0.tx_req.trigger           = DMA_TRIGGER_MNEM(UCB0TXIFG0);
 +  SPIDB0.rx_req.trigger           = DMA_TRIGGER_MNEM(UCB0RXIFG0);
 +  SPIDB0.tx_req.dest_addr         = &(SPIDB0.regs->txbuf);
 +  SPIDB0.rx_req.source_addr       = &(SPIDB0.regs->rxbuf);
 +  SPIDB0.tx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDB0.rx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDB0.tx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDB0.rx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDB0.tx_req.callback.callback = NULL;
 +  SPIDB0.tx_req.callback.args     = NULL;
 +  SPIDB0.rx_req.callback.callback = spi_lld_end_of_transfer;
 +  SPIDB0.rx_req.callback.args     = &SPIDB0;
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB1 == TRUE
 +  /* Driver initialization.*/
 +  spiObjectInit(&SPIDB1);
 +  SPIDB1.regs                     = (msp430x_spi_reg_t *)(&UCB1CTLW0);
 +  SPIDB1.ifg                      = (volatile uint16_t *)&UCB1IFG;
 +  SPIDB1.tx_req.trigger           = DMA_TRIGGER_MNEM(UCB1TXIFG0);
 +  SPIDB1.rx_req.trigger           = DMA_TRIGGER_MNEM(UCB1RXIFG0);
 +  SPIDB1.tx_req.dest_addr         = &(SPIDB1.regs->txbuf);
 +  SPIDB1.rx_req.source_addr       = &(SPIDB1.regs->rxbuf);
 +  SPIDB1.tx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDB1.rx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDB1.tx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDB1.rx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDB1.tx_req.callback.callback = NULL;
 +  SPIDB1.tx_req.callback.args     = NULL;
 +  SPIDB1.rx_req.callback.callback = spi_lld_end_of_transfer;
 +  SPIDB1.rx_req.callback.args     = &SPIDB1;
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB2 == TRUE
 +  /* Driver initialization.*/
 +  spiObjectInit(&SPIDB2);
 +  SPIDB2.regs                     = (msp430x_spi_reg_t *)(&UCB2CTLW0);
 +  SPIDB2.ifg                      = (volatile uint16_t *)&UCB2IFG;
 +  SPIDB2.tx_req.trigger           = DMA_TRIGGER_MNEM(UCB2TXIFG0);
 +  SPIDB2.rx_req.trigger           = DMA_TRIGGER_MNEM(UCB2RXIFG0);
 +  SPIDB2.tx_req.dest_addr         = &(SPIDB2.regs->txbuf);
 +  SPIDB2.rx_req.source_addr       = &(SPIDB2.regs->rxbuf);
 +  SPIDB2.tx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDB2.rx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDB2.tx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDB2.rx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDB2.tx_req.callback.callback = NULL;
 +  SPIDB2.tx_req.callback.args     = NULL;
 +  SPIDB2.rx_req.callback.callback = spi_lld_end_of_transfer;
 +  SPIDB2.rx_req.callback.args     = &SPIDB2;
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB3 == TRUE
 +  /* Driver initialization.*/
 +  spiObjectInit(&SPIDB3);
 +  SPIDB3.regs                     = (msp430x_spi_reg_t *)(&UCB3CTLW0);
 +  SPIDB3.ifg                      = (volatile uint16_t *)&UCB3IFG;
 +  SPIDB3.tx_req.trigger           = DMA_TRIGGER_MNEM(UCB3TXIFG0);
 +  SPIDB3.rx_req.trigger           = DMA_TRIGGER_MNEM(UCB3RXIFG0);
 +  SPIDB3.tx_req.dest_addr         = &(SPIDB3.regs->txbuf);
 +  SPIDB3.rx_req.source_addr       = &(SPIDB3.regs->rxbuf);
 +  SPIDB3.tx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDB3.rx_req.data_mode         = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
 +  SPIDB3.tx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDB3.rx_req.transfer_mode     = MSP430X_DMA_SINGLE;
 +  SPIDB3.tx_req.callback.callback = NULL;
 +  SPIDB3.tx_req.callback.args     = NULL;
 +  SPIDB3.rx_req.callback.callback = spi_lld_end_of_transfer;
 +  SPIDB3.rx_req.callback.args     = &SPIDB3;
 +#endif
 +}
 +
 +/**
 + * @brief   Configures and activates the SPI peripheral.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + *
 + * @notapi
 + */
 +void spi_lld_start(SPIDriver * spip) {
 +
 +  if (spip->state == SPI_STOP) {
 +/* Enables the peripheral.*/
 +#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE
 +    /* Claim DMA streams here */
 +    bool b;
 +    if (spip->config->dmatx_index < MSP430X_DMA_CHANNELS) {
 +      b = dmaAcquire(&(spip->dmatx), spip->config->dmatx_index);
 +      osalDbgAssert(!b, "stream already allocated");
 +    }
 +    if (spip->config->dmarx_index < MSP430X_DMA_CHANNELS) {
 +      b = dmaAcquire(&(spip->dmarx), spip->config->dmarx_index);
 +      osalDbgAssert(!b, "stream already allocated");
 +    }
 +#endif /* MSP430X_SPI_EXCLUSIVE_DMA */
 +  }
 +  uint16_t brw = 0;
 +  uint8_t ssel = 0;
 +#if MSP430X_SPI_USE_SPIA0
 +  if (spip == &SPIDA0) {
 +    brw  = MSP430X_SPIA0_CLK_FREQ / spip->config->bit_rate;
 +    ssel = MSP430X_SPIA0_UCSSEL;
 +  }
 +#endif
 +#if MSP430X_SPI_USE_SPIA1
 +  if (spip == &SPIDA1) {
 +    brw  = MSP430X_SPIA1_CLK_FREQ / spip->config->bit_rate;
 +    ssel = MSP430X_SPIA1_UCSSEL;
 +  }
 +#endif
 +#if MSP430X_SPI_USE_SPIA2
 +  if (spip == &SPIDA2) {
 +    brw  = MSP430X_SPIA2_CLK_FREQ / spip->config->bit_rate;
 +    ssel = MSP430X_SPIA2_UCSSEL;
 +  }
 +#endif
 +#if MSP430X_SPI_USE_SPIA3
 +  if (spip == &SPIDA3) {
 +    brw  = MSP430X_SPIA3_CLK_FREQ / spip->config->bit_rate;
 +    ssel = MSP430X_SPIA3_UCSSEL;
 +  }
 +#endif
 +#if MSP430X_SPI_USE_SPIB0
 +  if (spip == &SPIDB0) {
 +    brw  = MSP430X_SPIB0_CLK_FREQ / spip->config->bit_rate;
 +    ssel = MSP430X_SPIB0_UCSSEL;
 +  }
 +#endif
 +#if MSP430X_SPI_USE_SPIB1
 +  if (spip == &SPIDB1) {
 +    brw  = MSP430X_SPIB1_CLK_FREQ / spip->config->bit_rate;
 +    ssel = MSP430X_SPIB1_UCSSEL;
 +  }
 +#endif
 +#if MSP430X_SPI_USE_SPIB2
 +  if (spip == &SPIDB2) {
 +    brw  = MSP430X_SPIB2_CLK_FREQ / spip->config->bit_rate;
 +    ssel = MSP430X_SPIB2_UCSSEL;
 +  }
 +#endif
 +#if MSP430X_SPI_USE_SPIB3
 +  if (spip == &SPIDB3) {
 +    brw  = MSP430X_SPIB3_CLK_FREQ / spip->config->bit_rate;
 +    ssel = MSP430X_SPIB3_UCSSEL;
 +  }
 +#endif
 +  /* Configures the peripheral.*/
 +  spip->regs->ctlw0 = UCSWRST;
 +  spip->regs->brw   = brw;
 +  spip->regs->ctlw0 =
 +      (spip->config->spi_mode << 14) | (spip->config->bit_order << 13) |
 +      (spip->config->data_size << 12) | (UCMST) |
 +      ((spip->config->ss_line ? 0 : 2) << 9) | (UCSYNC) | (ssel) | (UCSTEM);
 +  *(spip->ifg) = 0;
 +}
 +
 +/**
 + * @brief   Deactivates the SPI peripheral.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + *
 + * @notapi
 + */
 +void spi_lld_stop(SPIDriver * spip) {
 +
 +  if (spip->state == SPI_READY) {
 +/* Disables the peripheral.*/
 +#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE
 +    dmaRelease(&(spip->dmatx));
 +    dmaRelease(&(spip->dmarx));
 +#endif
 +    spip->regs->ctlw0 = UCSWRST;
 +  }
 +}
 +
 +/**
 + * @brief   Asserts the slave select signal and prepares for transfers.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + *
 + * @notapi
 + */
 +void spi_lld_select(SPIDriver * spip) {
 +
 +  if (spip->config->ss_line) {
 +    palClearLine(spip->config->ss_line);
 +  }
 +}
 +
 +/**
 + * @brief   Deasserts the slave select signal.
 + * @details The previously selected peripheral is unselected.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + *
 + * @notapi
 + */
 +void spi_lld_unselect(SPIDriver * spip) {
 +
 +  if (spip->config->ss_line) {
 +    palSetLine(spip->config->ss_line);
 +  }
 +}
 +
 +/**
 + * @brief   Ignores data on the SPI bus.
 + * @details This asynchronous function starts the transmission of a series of
 + *          idle bytes on the SPI bus and ignores the received data.
 + * @post    At the end of the operation the configured callback is invoked.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + * @param[in] n         number of bytes to be ignored
 + *
 + * @notapi
 + */
 +void spi_lld_ignore(SPIDriver * spip, size_t n) {
 +
 +  spip->tx_req.source_addr = &dummytx;
 +  spip->tx_req.size        = n;
 +  spip->tx_req.addr_mode   = 0;
 +
 +  spip->rx_req.dest_addr = &dummyrx;
 +  spip->rx_req.size      = n;
 +  spip->rx_req.addr_mode = 0;
 +
 +  init_transfer(spip);
 +}
 +
 +/**
 + * @brief   Exchanges data on the SPI bus.
 + * @details This asynchronous function starts a simultaneous transmit/receive
 + *          operation.
 + * @post    At the end of the operation the configured callback is invoked.
 + * @note    The buffers are organized as uint8_t arrays for data sizes below or
 + *          equal to 8 bits else it is organized as uint16_t arrays.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + * @param[in] n         number of words to be exchanged
 + * @param[in] txbuf     the pointer to the transmit buffer
 + * @param[out] rxbuf    the pointer to the receive buffer
 + *
 + * @notapi
 + */
 +void spi_lld_exchange(SPIDriver * spip,
 +                      size_t n,
 +                      const void * txbuf,
 +                      void * rxbuf) {
 +
 +  spip->tx_req.source_addr = txbuf;
 +  spip->tx_req.size        = n;
 +  spip->tx_req.addr_mode   = MSP430X_DMA_SRCINCR;
 +
 +  spip->rx_req.dest_addr = rxbuf;
 +  spip->rx_req.size      = n;
 +  spip->rx_req.addr_mode = MSP430X_DMA_DSTINCR;
 +
 +  init_transfer(spip);
 +}
 +
 +/**
 + * @brief   Sends data over the SPI bus.
 + * @details This asynchronous function starts a transmit operation.
 + * @post    At the end of the operation the configured callback is invoked.
 + * @note    The buffers are organized as uint8_t arrays for data sizes below or
 + *          equal to 8 bits else it is organized as uint16_t arrays.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + * @param[in] n         number of words to send
 + * @param[in] txbuf     the pointer to the transmit buffer
 + *
 + * @notapi
 + */
 +void spi_lld_send(SPIDriver * spip, size_t n, const void * txbuf) {
 +
 +  spip->tx_req.source_addr = txbuf;
 +  spip->tx_req.size        = n;
 +  spip->tx_req.addr_mode   = MSP430X_DMA_SRCINCR;
 +
 +  spip->rx_req.dest_addr = &dummyrx;
 +  spip->rx_req.size      = n;
 +  spip->rx_req.addr_mode = 0;
 +
 +  init_transfer(spip);
 +}
 +
 +/**
 + * @brief   Receives data from the SPI bus.
 + * @details This asynchronous function starts a receive operation.
 + * @post    At the end of the operation the configured callback is invoked.
 + * @note    The buffers are organized as uint8_t arrays for data sizes below or
 + *          equal to 8 bits else it is organized as uint16_t arrays.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + * @param[in] n         number of words to receive
 + * @param[out] rxbuf    the pointer to the receive buffer
 + *
 + * @notapi
 + */
 +void spi_lld_receive(SPIDriver * spip, size_t n, void * rxbuf) {
 +
 +  spip->tx_req.source_addr = &dummytx;
 +  spip->tx_req.size        = n;
 +  spip->tx_req.addr_mode   = 0;
 +
 +  spip->rx_req.dest_addr = rxbuf;
 +  spip->rx_req.size      = n;
 +  spip->rx_req.addr_mode = MSP430X_DMA_DSTINCR;
 +
 +  init_transfer(spip);
 +}
 +
 +/**
 + * @brief   Exchanges one frame using a polled wait.
 + * @details This synchronous function exchanges one frame using a polled
 + *          synchronization method. This function is useful when exchanging
 + *          small amount of data on high speed channels, usually in this
 + *          situation is much more efficient just wait for completion using
 + *          polling than suspending the thread waiting for an interrupt.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object
 + * @param[in] frame     the data frame to send over the SPI bus
 + * @return              The received data frame from the SPI bus.
 + */
 +uint16_t spi_lld_polled_exchange(SPIDriver * spip, uint16_t frame) {
 +
 +  osalDbgAssert(!(frame & 0xFF00U), "16-bit transfers not supported");
 +
 +  while (!(*(spip->ifg) & UCTXIFG))
 +    ;
 +  spip->regs->txbuf = frame;
 +  while (!(*(spip->ifg) & UCRXIFG))
 +    ;
 +  return spip->regs->rxbuf;
 +}
 +
 +#endif /* HAL_USE_SPI == TRUE */
 +
 +/** @} */
 diff --git a/os/hal/ports/MSP430X/hal_spi_lld.h b/os/hal/ports/MSP430X/hal_spi_lld.h new file mode 100644 index 0000000..ebf14c8 --- /dev/null +++ b/os/hal/ports/MSP430X/hal_spi_lld.h @@ -0,0 +1,642 @@ +/*
 +    ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle
 +
 +    Licensed under the Apache License, Version 2.0 (the "License");
 +    you may not use this file except in compliance with the License.
 +    You may obtain a copy of the License at
 +
 +        http://www.apache.org/licenses/LICENSE-2.0
 +
 +    Unless required by applicable law or agreed to in writing, software
 +    distributed under the License is distributed on an "AS IS" BASIS,
 +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 +    See the License for the specific language governing permissions and
 +    limitations under the License.
 +*/
 +
 +/**
 + * @file    hal_spi_lld.h
 + * @brief   MSP430X SPI subsystem low level driver header.
 + *
 + * @addtogroup SPI
 + * @{
 + */
 +
 +#ifndef HAL_SPI_LLD_H
 +#define HAL_SPI_LLD_H
 +
 +#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
 +
 +#include "hal_dma_lld.h"
 +/*===========================================================================*/
 +/* Driver constants.                                                         */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Driver pre-compile time settings.                                         */
 +/*===========================================================================*/
 +
 +/**
 + * @name    MSP430X configuration options
 + * @{
 + */
 +/**
 + * @brief   SPIA0 driver enable switch.
 + * @details If set to @p TRUE the support for SPIA0 is included.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_USE_SPIA0) || defined(__DOXYGEN__)
 +#define MSP430X_SPI_USE_SPIA0                  FALSE
 +#endif
 +
 +/**
 + * @brief   SPIA1 driver enable switch.
 + * @details If set to @p TRUE the support for SPIA1 is included.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_USE_SPIA1) || defined(__DOXYGEN__)
 +#define MSP430X_SPI_USE_SPIA1                  FALSE
 +#endif
 +
 +/**
 + * @brief   SPIA2 driver enable switch.
 + * @details If set to @p TRUE the support for SPIA2 is included.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_USE_SPIA2) || defined(__DOXYGEN__)
 +#define MSP430X_SPI_USE_SPIA2                  FALSE
 +#endif
 +
 +/**
 + * @brief   SPIA3 driver enable switch.
 + * @details If set to @p TRUE the support for SPIA3 is included.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_USE_SPIA3) || defined(__DOXYGEN__)
 +#define MSP430X_SPI_USE_SPIA3                  FALSE
 +#endif
 +
 +/**
 + * @brief   SPIB0 driver enable switch.
 + * @details If set to @p TRUE the support for SPIB0 is included.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_USE_SPIB0) || defined(__DOXYGEN__)
 +#define MSP430X_SPI_USE_SPIB0                  FALSE
 +#endif
 +
 +/**
 + * @brief   SPIB1 driver enable switch.
 + * @details If set to @p TRUE the support for SPIB1 is included.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_USE_SPIB1) || defined(__DOXYGEN__)
 +#define MSP430X_SPI_USE_SPIB1                  FALSE
 +#endif
 +
 +/**
 + * @brief   SPIB2 driver enable switch.
 + * @details If set to @p TRUE the support for SPIB2 is included.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_USE_SPIB2) || defined(__DOXYGEN__)
 +#define MSP430X_SPI_USE_SPIB2                  FALSE
 +#endif
 +
 +/**
 + * @brief   SPIB3 driver enable switch.
 + * @details If set to @p TRUE the support for SPIB3 is included.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_USE_SPIB3) || defined(__DOXYGEN__)
 +#define MSP430X_SPI_USE_SPIB3                  FALSE
 +#endif
 +
 +/**
 + * @brief   Exclusive DMA enable switch.
 + * @details If set to @p TRUE the support for exclusive DMA is included.
 + * @note    This increases the size of the compiled executable somewhat.
 + * @note    The default is @p FALSE.
 + */
 +#if !defined(MSP430X_SPI_EXCLUSIVE_DMA) | defined(__DOXYGEN__)
 +#define MSP430X_SPI_EXCLUSIVE_DMA              FALSE
 +#endif
 +
 +/**
 + * @brief   SPIA0 clock source switch.
 + * @details Sets the clock source for SPIA0.
 + * @note    Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
 + * @note    The default is @p MSP430X_SMCLK_SRC.
 + */
 +#if !defined(MSP430X_SPIA0_CLK_SRC)
 +  #define MSP430X_SPIA0_CLK_SRC MSP430X_SMCLK_SRC
 +#endif
 +
 +/**
 + * @brief   SPIA1 clock source switch.
 + * @details Sets the clock source for SPIA1.
 + * @note    Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
 + * @note    The default is @p MSP430X_SMCLK_SRC.
 + */
 +#if !defined(MSP430X_SPIA1_CLK_SRC)
 +  #define MSP430X_SPIA1_CLK_SRC MSP430X_SMCLK_SRC
 +#endif
 +
 +/**
 + * @brief   SPIA2 clock source switch.
 + * @details Sets the clock source for SPIA2.
 + * @note    Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
 + * @note    The default is @p MSP430X_SMCLK_SRC.
 + */
 +#if !defined(MSP430X_SPIA2_CLK_SRC)
 +  #define MSP430X_SPIA2_CLK_SRC MSP430X_SMCLK_SRC
 +#endif
 +
 +/**
 + * @brief   SPIA3 clock source switch.
 + * @details Sets the clock source for SPIA3.
 + * @note    Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
 + * @note    The default is @p MSP430X_SMCLK_SRC.
 + */
 +#if !defined(MSP430X_SPIA3_CLK_SRC)
 +  #define MSP430X_SPIA3_CLK_SRC MSP430X_SMCLK_SRC
 +#endif
 +
 +/**
 + * @brief   SPIB0 clock source switch.
 + * @details Sets the clock source for SPIB0.
 + * @note    Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
 + * @note    The default is @p MSP430X_SMCLK_SRC.
 + */
 +#if !defined(MSP430X_SPIB0_CLK_SRC)
 +  #define MSP430X_SPIB0_CLK_SRC MSP430X_SMCLK_SRC
 +#endif
 +
 +/**
 + * @brief   SPIB1 clock source switch.
 + * @details Sets the clock source for SPIB1.
 + * @note    Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
 + * @note    The default is @p MSP430X_SMCLK_SRC.
 + */
 +#if !defined(MSP430X_SPIB1_CLK_SRC)
 +  #define MSP430X_SPIB1_CLK_SRC MSP430X_SMCLK_SRC
 +#endif
 +
 +/**
 + * @brief   SPIB2 clock source switch.
 + * @details Sets the clock source for SPIB2.
 + * @note    Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
 + * @note    The default is @p MSP430X_SMCLK_SRC.
 + */
 +#if !defined(MSP430X_SPIB2_CLK_SRC)
 +  #define MSP430X_SPIB2_CLK_SRC MSP430X_SMCLK_SRC
 +#endif
 +
 +/**
 + * @brief   SPIB3 clock source switch.
 + * @details Sets the clock source for SPIB3.
 + * @note    Legal values are @p MSP430X_SMCLK_SRC or @p MSP430X_ACLK_SRC.
 + * @note    The default is @p MSP430X_SMCLK_SRC.
 + */
 +#if !defined(MSP430X_SPIB3_CLK_SRC)
 +  #define MSP430X_SPIB3_CLK_SRC MSP430X_SMCLK_SRC
 +#endif
 +/** @} */
 +
 +/*===========================================================================*/
 +/* Derived constants and error checks.                                       */
 +/*===========================================================================*/
 +
 +#if MSP430X_SPI_USE_SPIA0 && !defined(__MSP430_HAS_EUSCI_A0__)
 +  #error "Cannot find MSP430X_USCI module to use for SPIA0"
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA1 && !defined(__MSP430_HAS_EUSCI_A1__)
 +  #error "Cannot find MSP430X_USCI module to use for SPIA1"
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA2 && !defined(__MSP430_HAS_EUSCI_A2__)
 +  #error "Cannot find MSP430X_USCI module to use for SPIA2"
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA3 && !defined(__MSP430_HAS_EUSCI_A3__)
 +  #error "Cannot find MSP430X_USCI module to use for SPIA3"
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB0 && !defined(__MSP430_HAS_EUSCI_B0__)
 +  #error "Cannot find MSP430X_USCI module to use for SPIB0"
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB1 && !defined(__MSP430_HAS_EUSCI_B1__)
 +  #error "Cannot find MSP430X_USCI module to use for SPIB1"
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB2 && !defined(__MSP430_HAS_EUSCI_B2__)
 +  #error "Cannot find MSP430X_USCI module to use for SPIB2"
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB3 && !defined(__MSP430_HAS_EUSCI_B3__)
 +  #error "Cannot find MSP430X_USCI module to use for SPIB3"
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA0
 +  #ifdef MSP430X_USCI_A0_USED
 +    #error "USCI module A0 already in use - SPIA0 not available"
 +  #else
 +    #define MSP430X_USCI_A0_USED
 +  #endif
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA1
 +  #ifdef MSP430X_USCI_A1_USED
 +    #error "USCI module A1 already in use - SPIA1 not available"
 +  #else
 +    #define MSP430X_USCI_A1_USED
 +  #endif
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA2
 +  #ifdef MSP430X_USCI_A2_USED
 +    #error "USCI module A2 already in use - SPIA2 not available"
 +  #else
 +    #define MSP430X_USCI_A2_USED
 +  #endif
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIA3
 +  #ifdef MSP430X_USCI_A3_USED
 +    #error "USCI module A3 already in use - SPIA3 not available"
 +  #else
 +    #define MSP430X_USCI_A3_USED
 +  #endif
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB0
 +  #ifdef MSP430X_USCI_B0_USED
 +    #error "USCI module B0 already in use - SPIB0 not available"
 +  #else
 +    #define MSP430X_USCI_B0_USED
 +  #endif
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB1
 +  #ifdef MSP430X_USCI_B1_USED
 +    #error "USCI module B1 already in use - SPIB1 not available"
 +  #else
 +    #define MSP430X_USCI_B1_USED
 +  #endif
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB2
 +  #ifdef MSP430X_USCI_B2_USED
 +    #error "USCI module B2 already in use - SPIB2 not available"
 +  #else
 +    #define MSP430X_USCI_B2_USED
 +  #endif
 +#endif
 +
 +#if MSP430X_SPI_USE_SPIB3
 +  #ifdef MSP430X_USCI_B3_USED
 +    #error "USCI module B3 already in use - SPIB3 not available"
 +  #else
 +    #define MSP430X_USCI_B3_USED
 +  #endif
 +#endif
 +
 +#if defined(MSP430X_SPIA0_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIA0 TX, but requested index is invalid"
 +#endif
 +#if defined(MSP430X_SPIA0_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIA0 RX, but requested index is invalid"
 +#endif
 +
 +#if defined(MSP430X_SPIA1_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIA1 TX, but requested index is invalid"
 +#endif
 +#if defined(MSP430X_SPIA1_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIA1 RX, but requested index is invalid"
 +#endif
 +
 +#if defined(MSP430X_SPIA2_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIA2 TX, but requested index is invalid"
 +#endif
 +#if defined(MSP430X_SPIA2_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIA2 RX, but requested index is invalid"
 +#endif
 +
 +#if defined(MSP430X_SPIA3_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIA3 TX, but requested index is invalid"
 +#endif
 +#if defined(MSP430X_SPIA3_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIA3 RX, but requested index is invalid"
 +#endif
 +
 +#if defined(MSP430X_SPIB0_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIB0 TX, but requested index is invalid"
 +#endif
 +#if defined(MSP430X_SPIB0_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIB0 RX, but requested index is invalid"
 +#endif
 +
 +#if defined(MSP430X_SPIB1_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIB1 TX, but requested index is invalid"
 +#endif
 +#if defined(MSP430X_SPIB1_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIB1 RX, but requested index is invalid"
 +#endif
 +
 +#if defined(MSP430X_SPIB2_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIB2 TX, but requested index is invalid"
 +#endif
 +#if defined(MSP430X_SPIB2_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIB2 RX, but requested index is invalid"
 +#endif
 +
 +#if defined(MSP430X_SPIB3_TX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIB3 TX, but requested index is invalid"
 +#endif
 +#if defined(MSP430X_SPIB3_RX_DMA) && (MSP430X_SPI_DMA >= MSP430X_DMA_CHANNELS)
 +  #error "Requested DMA for SPIB3 RX, but requested index is invalid"
 +#endif
 +
 +/* TODO figure out a way to check for conflicting DMA channels */
 +
 +#if MSP430X_SPIA0_CLK_SRC == MSP430X_ACLK_SRC
 +  #define MSP430X_SPIA0_CLK_FREQ MSP430X_ACLK_FREQ
 +  #define MSP430X_SPIA0_UCSSEL UCSSEL__ACLK
 +#elif MSP430X_SPIA0_CLK_SRC == MSP430X_SMCLK_SRC
 +  #define MSP430X_SPIA0_CLK_FREQ MSP430X_SMCLK_FREQ
 +  #define MSP430X_SPIA0_UCSSEL UCSSEL__SMCLK
 +#endif
 +
 +#if MSP430X_SPIA1_CLK_SRC == MSP430X_ACLK_SRC
 +  #define MSP430X_SPIA1_CLK_FREQ MSP430X_ACLK_FREQ
 +  #define MSP430X_SPIA1_UCSSEL UCSSEL__ACLK
 +#elif MSP430X_SPIA1_CLK_SRC == MSP430X_SMCLK_SRC
 +  #define MSP430X_SPIA1_CLK_FREQ MSP430X_SMCLK_FREQ
 +  #define MSP430X_SPIA1_UCSSEL UCSSEL__SMCLK
 +#endif
 +
 +#if MSP430X_SPIA2_CLK_SRC == MSP430X_ACLK_SRC
 +  #define MSP430X_SPIA2_CLK_FREQ MSP430X_ACLK_FREQ
 +  #define MSP430X_SPIA2_UCSSEL UCSSEL__ACLK
 +#elif MSP430X_SPIA2_CLK_SRC == MSP430X_SMCLK_SRC
 +  #define MSP430X_SPIA2_CLK_FREQ MSP430X_SMCLK_FREQ
 +  #define MSP430X_SPIA2_UCSSEL UCSSEL__SMCLK
 +#endif
 +
 +#if MSP430X_SPIA3_CLK_SRC == MSP430X_ACLK_SRC
 +  #define MSP430X_SPIA3_CLK_FREQ MSP430X_ACLK_FREQ
 +  #define MSP430X_SPIA3_UCSSEL UCSSEL__ACLK
 +#elif MSP430X_SPIA3_CLK_SRC == MSP430X_SMCLK_SRC
 +  #define MSP430X_SPIA3_CLK_FREQ MSP430X_SMCLK_FREQ
 +  #define MSP430X_SPIA3_UCSSEL UCSSEL__SMCLK
 +#endif
 +
 +#if MSP430X_SPIB0_CLK_SRC == MSP430X_ACLK_SRC
 +  #define MSP430X_SPIB0_CLK_FREQ MSP430X_ACLK_FREQ
 +  #define MSP430X_SPIB0_UCSSEL UCSSEL__ACLK
 +#elif MSP430X_SPIB0_CLK_SRC == MSP430X_SMCLK_SRC
 +  #define MSP430X_SPIB0_CLK_FREQ MSP430X_SMCLK_FREQ
 +  #define MSP430X_SPIB0_UCSSEL UCSSEL__SMCLK
 +#endif
 +
 +#if MSP430X_SPIB1_CLK_SRC == MSP430X_ACLK_SRC
 +  #define MSP430X_SPIB1_CLK_FREQ MSP430X_ACLK_FREQ
 +  #define MSP430X_SPIB1_UCSSEL UCSSEL__ACLK
 +#elif MSP430X_SPIB1_CLK_SRC == MSP430X_SMCLK_SRC
 +  #define MSP430X_SPIB1_CLK_FREQ MSP430X_SMCLK_FREQ
 +  #define MSP430X_SPIB1_UCSSEL UCSSEL__SMCLK
 +#endif
 +
 +#if MSP430X_SPIB2_CLK_SRC == MSP430X_ACLK_SRC
 +  #define MSP430X_SPIB2_CLK_FREQ MSP430X_ACLK_FREQ
 +  #define MSP430X_SPIB2_UCSSEL UCSSEL__ACLK
 +#elif MSP430X_SPIB2_CLK_SRC == MSP430X_SMCLK_SRC
 +  #define MSP430X_SPIB2_CLK_FREQ MSP430X_SMCLK_FREQ
 +  #define MSP430X_SPIB2_UCSSEL UCSSEL__SMCLK
 +#endif
 +
 +#if MSP430X_SPIB3_CLK_SRC == MSP430X_ACLK_SRC
 +  #define MSP430X_SPIB3_CLK_FREQ MSP430X_ACLK_FREQ
 +  #define MSP430X_SPIB3_UCSSEL UCSSEL__ACLK
 +#elif MSP430X_SPIB3_CLK_SRC == MSP430X_SMCLK_SRC
 +  #define MSP430X_SPIB3_CLK_FREQ MSP430X_SMCLK_FREQ
 +  #define MSP430X_SPIB3_UCSSEL UCSSEL__SMCLK
 +#endif
 +
 +/*===========================================================================*/
 +/* Driver data structures and types.                                         */
 +/*===========================================================================*/
 +
 +/**
 + * @brief   Type of a structure representing an SPI driver.
 + */
 +typedef struct SPIDriver SPIDriver;
 +
 +/**
 + * @brief   SPI notification callback type.
 + *
 + * @param[in] spip      pointer to the @p SPIDriver object triggering the
 + *                      callback
 + */
 +typedef void (*spicallback_t)(SPIDriver *spip);
 +
 +/**
 + * @brief   Enumerated type for SPI bit order.
 + */
 +typedef enum {
 +  MSP430X_SPI_BO_LSB = 0,
 +  MSP430X_SPI_BO_MSB = 1
 +} msp430x_spi_bit_order_t;
 +
 +/**
 + * @brief   Enumerated type for SPI data size.
 + */
 +typedef enum {
 +  MSP430X_SPI_DS_EIGHT = 0,
 +  MSP430X_SPI_DS_SEVEN = 1
 +} msp430x_spi_data_size_t;
 +
 +/**
 + * @brief   Driver configuration structure.
 + * @note    Implementations may extend this structure to contain more,
 + *          architecture dependent, fields.
 + */
 +typedef struct {
 +  /**
 +   * @brief Operation complete callback or @p NULL.
 +   */
 +  spicallback_t             end_cb;
 +  /* End of the mandatory fields.*/
 +  /**
 +   * @brief The chip select line.
 +   * @note  This may be PAL_NOLINE to indicate that hardware chip select is used.
 +   */
 +  ioline_t                  ss_line;
 +  /**
 +   * @brief The bit rate of the SPI interface.
 +   * @note  Nearest available rate is used.
 +   */
 +  uint32_t                  bit_rate;
 +  /**
 +   * @brief The bit order of the peripheral - LSB or MSB first.
 +   */
 +  msp430x_spi_bit_order_t bit_order;
 +  /**
 +   * @brief The data size of the peripheral - 7 or 8 bits.
 +   */
 +  msp430x_spi_data_size_t data_size;
 +  /**
 +   * @brief The SPI mode to use - 0 through 3.
 +   */
 +  uint8_t spi_mode;
 +#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE || defined(__DOXYGEN__)
 +  /**
 +   * @brief The index of the TX DMA channel.
 +   * @note  This may be >MSP430X_DMA_CHANNELS to indicate that exclusive DMA is not used.
 +   */
 +  uint8_t dmatx_index;
 +  /**
 +   * @brief The index of the RX DMA channel.
 +   * @note  This may be >MSP430X_DMA_CHANNELS to indicate that exclusive DMA is not used.
 +   */
 +  uint8_t dmarx_index;
 +#endif
 +} SPIConfig;
 +
 +/**
 + * @brief   MSP430X SPI register structure.
 + */
 +typedef struct {
 +  uint16_t ctlw0;
 +  uint16_t _padding0;
 +  uint16_t _padding1;
 +  uint16_t brw;
 +  uint16_t statw_b;
 +  uint16_t statw_a;
 +  uint16_t rxbuf;
 +  uint16_t txbuf;
 +} msp430x_spi_reg_t;
 +
 +/**
 + * @brief   Structure representing an SPI driver.
 + * @note    Implementations may extend this structure to contain more,
 + *          architecture dependent, fields.
 + */
 +struct SPIDriver {
 +  /**
 +   * @brief Driver state.
 +   */
 +  spistate_t                state;
 +  /**
 +   * @brief Current configuration data.
 +   */
 +  const SPIConfig           *config;
 +#if (SPI_USE_WAIT == TRUE) || defined(__DOXYGEN__)
 +  /**
 +   * @brief   Waiting thread.
 +   */
 +  thread_reference_t        thread;
 +#endif /* SPI_USE_WAIT */
 +#if (SPI_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
 +  /**
 +   * @brief   Mutex protecting the peripheral.
 +   */
 +  mutex_t                   mutex;
 +#endif
 +#if defined(SPI_DRIVER_EXT_FIELDS)
 +  SPI_DRIVER_EXT_FIELDS
 +#endif
 +  /* End of the mandatory fields.*/
 +  /**
 +   * @brief   Configuration registers.
 +   */
 +  msp430x_spi_reg_t * regs;
 +  /**
 +   * @brief   Interrupt flag register.
 +   */
 +  volatile uint16_t * ifg;
 +  /**
 +   * @brief   TX DMA request.
 +   */
 +  msp430x_dma_req_t tx_req;
 +  /**
 +   * @brief   RX DMA request.
 +   */
 +  msp430x_dma_req_t rx_req;
 +#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE || defined(__DOXYGEN__)
 +  /**
 +   * @brief   TX DMA stream.
 +   */
 +  msp430x_dma_ch_t dmatx;
 +  /**
 +   * @brief   RX DMA stream.
 +   */
 +  msp430x_dma_ch_t dmarx;
 +#endif
 +};
 +
 +/*===========================================================================*/
 +/* Driver macros.                                                            */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* External declarations.                                                    */
 +/*===========================================================================*/
 +
 +#if (MSP430X_SPI_USE_SPIA0 == TRUE) && !defined(__DOXYGEN__)
 +extern SPIDriver SPIDA0;
 +#endif
 +
 +#if (MSP430X_SPI_USE_SPIA1 == TRUE) && !defined(__DOXYGEN__)
 +extern SPIDriver SPIDA1;
 +#endif
 +
 +#if (MSP430X_SPI_USE_SPIA2 == TRUE) && !defined(__DOXYGEN__)
 +extern SPIDriver SPIDA2;
 +#endif
 +
 +#if (MSP430X_SPI_USE_SPIA3 == TRUE) && !defined(__DOXYGEN__)
 +extern SPIDriver SPIDA3;
 +#endif
 +
 +#if (MSP430X_SPI_USE_SPIB0 == TRUE) && !defined(__DOXYGEN__)
 +extern SPIDriver SPIDB0;
 +#endif
 +
 +#if (MSP430X_SPI_USE_SPIB1 == TRUE) && !defined(__DOXYGEN__)
 +extern SPIDriver SPIDB1;
 +#endif
 +
 +#if (MSP430X_SPI_USE_SPIB2 == TRUE) && !defined(__DOXYGEN__)
 +extern SPIDriver SPIDB2;
 +#endif
 +
 +#if (MSP430X_SPI_USE_SPIB3 == TRUE) && !defined(__DOXYGEN__)
 +extern SPIDriver SPIDB3;
 +#endif
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +  void spi_lld_init(void);
 +  void spi_lld_start(SPIDriver *spip);
 +  void spi_lld_stop(SPIDriver *spip);
 +  void spi_lld_select(SPIDriver *spip);
 +  void spi_lld_unselect(SPIDriver *spip);
 +  void spi_lld_ignore(SPIDriver *spip, size_t n);
 +  void spi_lld_exchange(SPIDriver *spip, size_t n,
 +                        const void *txbuf, void *rxbuf);
 +  void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
 +  void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
 +  uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* HAL_USE_SPI == TRUE */
 +
 +#endif /* HAL_SPI_LLD_H */
 +
 +/** @} */
 diff --git a/os/hal/ports/MSP430X/platform.mk b/os/hal/ports/MSP430X/platform.mk index 6947785..832814b 100644 --- a/os/hal/ports/MSP430X/platform.mk +++ b/os/hal/ports/MSP430X/platform.mk @@ -3,7 +3,8 @@ PLATFORMSRC = ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_lld.c \                ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_st_lld.c \
                ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_serial_lld.c \
                ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_pal_lld.c \
 -              ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_dma_lld.c 
 +              ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_dma_lld.c \
 +              ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X/hal_spi_lld.c 
  # Required include directories
  PLATFORMINC = ${CHIBIOS_CONTRIB}/os/hal/ports/MSP430X
 | 
