📄 dspi.c
字号:
* \param txb Buffer holding data to be written * \param rxb Buffer to hold read data * \param length Number of bytes to read/write * \return Zero for success; Non-zero otherwise. * * Write the buffer to the specified SPI device and read the receive * data into the receive buffer. The receive buffer and transmit * buffer pointers *can* point to the same buffer. This will stall to wait * for the DSPI to be available if it is busy with another transfer. */intspi_master_write_read(SPI_DEVICE *dev, uint8 *txb, uint8 *rxb, int length){ SPI_MSG_CHAIN m; SPI_MSG_LINK l; memset(&m, 0, sizeof(SPI_MSG_CHAIN)); m.device = dev; m.link = &l; memset(&l, 0, sizeof(SPI_MSG_LINK)); l.tx_buf = txb; l.rx_buf = rxb; l.length = length; l.next = NULL; /* Queue it up */ spi_master_enqueue(&m); /* Wait for the transfer to finish */ while (m.status != SPI_MSG_CHAIN_DONE) {}; return 0;}/********************************************************************//*! * Queue up a transfer * \param msg Message chain * \param sync Synchronous flag * \return Zero for success; Non-zero otherwise. * * Take a message chain as an argument and queue it up. If the sync flag * is TRUE, then stall until the message is transferred. Otherwise, * return. The caller may specify a callback function in the message * struct or poll the status in the message data structure. * * No checks are performed on the message data structure. Caller beware! */intspi_master_transfer(SPI_MSG_CHAIN *msg, int sync){ /* Queue it up */ spi_master_enqueue(msg); if (sync == TRUE) { /* Wait for the transfer to finish */ while (msg->status != SPI_MSG_CHAIN_DONE) {}; } return 0;}/********************************************************************//*! * Enqueue a message to be transferred by the SPI master * \param SPI_MSG_CHAIN Message to be transferred * \return Zero for success; Non-zero otherwise. * * Add the message to the SPI message queue. This routine * is asynchronous; it will not wait for the transfer to complete * before returning to the caller. */static intspi_master_enqueue(SPI_MSG_CHAIN *message){ queue_add(&drv_data.queue, (QNODE *)message); message->status = SPI_MSG_CHAIN_QUEUED; if (drv_data.status == SPI_DRIVER_IDLE) spi_master_tx();}/********************************************************************//*! * Interrupt handler for all DSPI interrupts */__interrupt__void spi_master_irq_handler (void){ uint32 dsr; dsr = MCF_DSPI_DSR; MCF_DSPI_DSR &= 0xFFFF0000; if (dsr & MCF_DSPI_DSR_RFDF) { drv_data.event_rfd++; } if (dsr & MCF_DSPI_DSR_RFOF) { drv_data.event_rfo++; } if (dsr & MCF_DSPI_DSR_TFFF) { drv_data.event_tff++; } if (dsr & MCF_DSPI_DSR_TFUF) { drv_data.event_tfu++; } if (dsr & MCF_DSPI_DSR_EOQF) { drv_data.event_eoq++; spi_master_rx(); spi_master_tx(); } if (dsr & MCF_DSPI_DSR_TCF) { drv_data.event_tc++; }} /********************************************************************/ /*! * Start or continue a DSPI transmit * \return Number of bytes stuffed into FIFO * * spi_master_tx() is called to start a new transfer (by spi_master_enqueue) * or to continue an existing or queued transfer (by interupt handler). */static intspi_master_tx (void){ int fifo, cnt, data, cs, dummy; uint32 pushr; if ((drv_data.status == SPI_DRIVER_IDLE) || ((drv_data.status == SPI_DRIVER_RUNNING) && (drv_data.chain->status == SPI_MSG_CHAIN_DONE))) { /* Pull the next message off the queue */ drv_data.chain = (SPI_MSG_CHAIN *)queue_remove(&drv_data.queue); if (drv_data.chain == NULL) { drv_data.status = SPI_DRIVER_IDLE; return 0; } ASSERT(drv_data.chain->link); drv_data.tx = drv_data.chain->link->tx_buf; drv_data.rx = drv_data.chain->link->rx_buf; drv_data.tx_end = (void *)((int)drv_data.tx + drv_data.chain->link->length); drv_data.rx_end = (void *)((int)drv_data.rx + drv_data.chain->link->length); drv_data.status = SPI_DRIVER_RUNNING; drv_data.chain->status = SPI_MSG_CHAIN_RUNNING; if (drv_data.chain->link->next == NULL) drv_data.last = drv_data.tx_end; else drv_data.last = NULL; } /* Calculate chip-select encoding */ if (drv_data.chain->device->cs_muxed) cs = drv_data.chain->device->cs << 16; else cs = 1 << (drv_data.chain->device->cs + 16); cnt = drv_data.tx_end - drv_data.tx; if (cnt > SPI_FIFO_SIZE) cnt = SPI_FIFO_SIZE; fifo = cnt; dummy = !drv_data.chain->link->tx_buf; pushr = 0 | MCF_DSPI_PUSHR_CONT | MCF_DSPI_PUSHR_CTAS(drv_data.chain->device->cs) | cs; while (cnt) { --cnt; /*! * \todo need some way to handle the case of an odd number of * bytes being transferred for an otherwise 16bit word transfer */ if (drv_data.chain->device->frame_size <= 8) { if (dummy) data = 0; else data = *(uint8*)drv_data.tx; drv_data.tx += 1; } else { if (dummy) data = 0; else data = *(uint16*)drv_data.tx; drv_data.tx += 2; } /* Mark end-of-queue */ if (0 == cnt) { pushr |= MCF_DSPI_PUSHR_EOQ; /* Clear continuous bit at the end of a message chain */ if (drv_data.tx == drv_data.last) pushr &= ~MCF_DSPI_PUSHR_CONT; } MCF_DSPI_PUSHR = pushr | MCF_DSPI_PUSHR_TXDATA(data); } return fifo; }/********************************************************************/ /*! * Pull data from the DSPI * \return Number of bytes stuffed into FIFO * * This routine is only called by the interrupt handler. Data is only * received following an EOQ interrupt which will occur after the tx routine * has placed real or fake data into the transmit FIFO and that data has * all been shifted out. At that time, the equivalent number receive bytes * will be available in the FIFO. */static intspi_master_rx (void){ int fifo, cnt, save; uint16 rx_data; cnt = drv_data.rx_end - drv_data.rx; if (cnt > SPI_FIFO_SIZE) cnt = SPI_FIFO_SIZE; fifo = cnt; save = (drv_data.chain->link->rx_buf != NULL); /* Pull data from receive FIFO */ while (cnt) { --cnt; rx_data = MCF_DSPI_POPR & 0xFFFF; /*! * \todo still need some way to handle the case of an odd number of * bytes being transferred for an otherwise 16bit word transfer */ if (drv_data.chain->device->frame_size <= 8) { if (save) *(uint8*)drv_data.rx = rx_data; drv_data.rx += 1; } else { if (save) *(uint16*)drv_data.rx = rx_data; drv_data.rx += 2; } } /* Check for end of chain or end of link */ if (drv_data.rx >= drv_data.rx_end) { drv_data.chain->link = drv_data.chain->link->next; if (drv_data.chain->link != NULL) { /* Update local pointers with info from next link */ drv_data.tx = drv_data.chain->link->tx_buf; drv_data.rx = drv_data.chain->link->rx_buf; drv_data.tx_end = (void *)((int)drv_data.tx + drv_data.chain->link->length); drv_data.rx_end = (void *)((int)drv_data.rx + drv_data.chain->link->length); drv_data.chain->status = SPI_MSG_CHAIN_RUNNING; if (drv_data.chain->link->next == NULL) drv_data.last = drv_data.tx_end; else drv_data.last = NULL; } else { drv_data.chain->status = SPI_MSG_CHAIN_DONE; if (drv_data.chain->callback != NULL) { /* Execute the callback function */ drv_data.chain->callback(drv_data.chain); } } } return fifo;}/********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -