Esempio n. 1
0
/** Write out data over the USART using DMA. Note that this function is not
 * reentrant and does not guard against DMA IRQs running at the same time which
 * will also cause spurious behaviours. Ensure that the calling function
 * appropriately prevents these things from happeing.
 *
 * \param data A pointer to the data to write out.
 * \param len  The number of bytes to write.
 *
 * \return The number of bytes that will be written, may be less than len.
 */
u32 usart_write_dma(u8 data[], u32 len) {
  /* Check if the write would cause a buffer overflow, if so only write up to
   * the end of the buffer. */
  u32 n_free = usart_tx_n_free();
  if (len > n_free)
    len = n_free;

  /* If there is no data to write, just return. */
  if (len == 0) return 0;

  u32 old_wr = wr;
  wr = (wr + len) % USART_TX_BUFFER_LEN;

  if (old_wr + len <= USART_TX_BUFFER_LEN) {
    memcpy(&buff[old_wr], data, len);
  } else {
    /* Deal with case where write wraps the buffer. */
    memcpy(&buff[old_wr], &data[0], USART_TX_BUFFER_LEN - old_wr);
    memcpy(&buff[0], &data[USART_TX_BUFFER_LEN-old_wr],
           len - (USART_TX_BUFFER_LEN - old_wr));
  }

  /* Check if there is a DMA transfer either in progress or waiting for its
   * interrupt to be serviced. Its very important to also check the interrupt
   * flag as EN will be cleared when the transfer finishes but we really need
   * to make sure the ISR has been run to finish up the bookkeeping for the
   * transfer. Also, make sure that this is done atomically without a DMA
   * interrupt squeezing in there. */
  if (!((DMA2_S7CR & DMA_SxCR_EN) || (DMA2_HISR & DMA_HISR_TCIF7)))
    dma_schedule();

  return len;
}
Esempio n. 2
0
u32 usart_support_write(void *sd, const u8 data[], u32 len)
{
  struct usart_tx_dma_state *s = &((struct usart_support_s *)sd)->tx;

  /* If there is no data to write, just return. */
  if (len == 0) return 0;

  chSysLock();

  /* Check if the write would cause a buffer overflow, if so only write up to
   * the end of the buffer. */
  u32 n_free = usart_tx_n_free(sd);
  if (len > n_free) {
    chSysUnlock();
    return 0;
  }

  u32 old_wr = s->wr;
  s->wr = (s->wr + len) % USART_TX_BUFFER_LEN;

  if (old_wr + len <= USART_TX_BUFFER_LEN)
    memcpy(&(s->buff[old_wr]), data, len);
  else {
    /* Deal with case where write wraps the buffer. */
    memcpy(&(s->buff[old_wr]), &data[0], USART_TX_BUFFER_LEN - old_wr);
    memcpy(&(s->buff[0]), &data[USART_TX_BUFFER_LEN - old_wr],
           len - (USART_TX_BUFFER_LEN - old_wr));
  }

  /* Check if there is a DMA transfer either in progress or waiting for its
   * interrupt to be serviced. Its very important to also check the interrupt
   * flag as EN will be cleared when the transfer finishes but we really need
   * to make sure the ISR has been run to finish up the bookkeeping for the
   * transfer. Also, make sure that this is done atomically without a DMA
   * interrupt squeezing in there. */
  if (!s->busy)
    dma_schedule(s);

  chSysUnlock();
  return len;
}