📄 dspi.c
字号:
/*! * \file dspi.c * \brief Driver for the DSPI module * \version $Revision: 1.3 $ * \author Michael Norman * * \todo add DMA support * \todo add slave support * \todo add support for advanced options (MTFE, FRZ, etc.) */#include "common.h"#include "clock.h"#include "queue.h"#include "dspi.h"/********************************************************************//*! Driver data */struct spi_driver_data drv_data = { .status = SPI_DRIVER_IDLE,};/********************************************************************//*! * \brief Initialize the DSPI module for Master mode * \return Zero for success; Non-zero otherwise. */intspi_master_init(void){ /* Initialize the driver data struct */ memset(&drv_data, 0, sizeof(struct spi_driver_data)); queue_init(&drv_data.queue); /* Enable pins for DSPI mode - chip-selects are enabled later */ MCF_GPIO_PAR_DSPI = 0 | MCF_GPIO_PAR_DSPI_SIN_SIN | MCF_GPIO_PAR_DSPI_SOUT_SOUT | MCF_GPIO_PAR_DSPI_SCK_SCK; /* Configure DSPI module */ MCF_DSPI_DMCR = 0 /* clear halt bit */ | MCF_DSPI_DMCR_MSTR /* master mode */ | MCF_DSPI_DMCR_CLRTXF /* clear Tx FIFO */ | MCF_DSPI_DMCR_CLRRXF; /* clear Rx FIFO */ /* Enable desired interrupts in DSPI module */ MCF_DSPI_DRSER = 0 | MCF_DSPI_DRSER_EOQFE; /* | MCF_DSPI_DRSER_RFDFS | MCF_DSPI_DRSER_RFDFE | MCF_DSPI_DRSER_RFOFE | MCF_DSPI_DRSER_TFFFS | MCF_DSPI_DRSER_TFFFE | MCF_DSPI_DRSER_TFUFE | MCF_DSPI_DRSER_TCFE; */ /* Enable DSPI interrupts in interrupt controller */ MCF_INTC1_ICR33 = MCF_INTC_ICR_IL(0x01); MCF_INTC1_ICR34 = MCF_INTC_ICR_IL(0x01); MCF_INTC1_ICR35 = MCF_INTC_ICR_IL(0x01); MCF_INTC1_ICR36 = MCF_INTC_ICR_IL(0x01); MCF_INTC1_ICR37 = MCF_INTC_ICR_IL(0x01); MCF_INTC1_ICR38 = MCF_INTC_ICR_IL(0x01); MCF_INTC1_ICR39 = MCF_INTC_ICR_IL(0x01); MCF_INTC1_IMRH &= ~(0 | MCF_INTC_IMRH_INT_MASK33 | MCF_INTC_IMRH_INT_MASK34 | MCF_INTC_IMRH_INT_MASK35 | MCF_INTC_IMRH_INT_MASK36 | MCF_INTC_IMRH_INT_MASK37 | MCF_INTC_IMRH_INT_MASK38 | MCF_INTC_IMRH_INT_MASK39); mcf5xxx_set_handler (128 + 33, (ADDRESS) spi_master_irq_handler); mcf5xxx_set_handler (128 + 34, (ADDRESS) spi_master_irq_handler); mcf5xxx_set_handler (128 + 35, (ADDRESS) spi_master_irq_handler); mcf5xxx_set_handler (128 + 36, (ADDRESS) spi_master_irq_handler); mcf5xxx_set_handler (128 + 37, (ADDRESS) spi_master_irq_handler); mcf5xxx_set_handler (128 + 38, (ADDRESS) spi_master_irq_handler); mcf5xxx_set_handler (128 + 39, (ADDRESS) spi_master_irq_handler); return 0;}/********************************************************************//*! * \brief Initialize SPI slave device interface * \todo finish this! * \param device SPI Device */intspi_master_device_init (SPI_DEVICE *device){ int i, j, temp; uint32 ctar = 0; int fbus = clock_get_fbus(); /* Enable appropriate pin for DSPI CS use */ switch (device->cs) { case 0: MCF_GPIO_PAR_DSPI |= MCF_GPIO_PAR_DSPI_PCS0_PCS0; if (device->cs_is) MCF_DSPI_DMCR |= MCF_DSPI_DMCR_PCSIS0; break; case 1: MCF_GPIO_PAR_DSPI |= MCF_GPIO_PAR_DSPI_PCS1_PCS1; if (device->cs_is) MCF_DSPI_DMCR |= MCF_DSPI_DMCR_PCSIS1; break; case 2: MCF_GPIO_PAR_DSPI |= MCF_GPIO_PAR_DSPI_PCS2_PCS2; if (device->cs_is) MCF_DSPI_DMCR |= MCF_DSPI_DMCR_PCSIS2; break; case 5: MCF_GPIO_PAR_DSPI |= MCF_GPIO_PAR_DSPI_PCS5_PCS5; if (device->cs_is) MCF_DSPI_DMCR |= MCF_DSPI_DMCR_PCSIS5; break; default: ASSERT(0); } /* frame size */ ASSERT ((device->frame_size >= 4) && (device->frame_size <= 16)); ctar |= MCF_DSPI_DCTAR_FMSZ(device->frame_size - 1); /* clock polarity and phase */ switch (device->mode) { case SPI_MODE_0: ctar |= 0 | MCF_DSPI_DCTAR_CPOL_LOW | MCF_DSPI_DCTAR_CPHA_LATCH_RISING; break; case SPI_MODE_1: ctar |= 0 | MCF_DSPI_DCTAR_CPOL_LOW | MCF_DSPI_DCTAR_CPHA_LATCH_FALLING; break; case SPI_MODE_2: ctar |= 0 | MCF_DSPI_DCTAR_CPOL_HIGH | MCF_DSPI_DCTAR_CPHA_LATCH_RISING; break; case SPI_MODE_3: ctar |= 0 | MCF_DSPI_DCTAR_CPOL_HIGH | MCF_DSPI_DCTAR_CPHA_LATCH_FALLING; break; default: ASSERT(0); } /* first bit */ if (device->fbit == SPI_FBIT_LSB) ctar |= MCF_DSPI_DCTAR_LSBFE; /* chip-select assertion to first clk edge delay */ temp = (device->delay_csclk * (fbus / 1000)) / 1000000; ASSERT(temp < 65536); /* need to implement prescaler in this case */ if (temp > 2) { /* Round scaler up to nearest power of two */ temp = (temp * 2) - 1; for (i = 0, j = temp; j != 1; j >>= 1, i++) {}; ctar |= MCF_DSPI_DCTAR_CSSCK(i - 1); } else { ctar |= MCF_DSPI_DCTAR_CSSCK(0); } /* last clk edge to chip-select deassertion delay */ temp = (device->delay_clkcs * (fbus / 1000)) / 1000000; ASSERT(temp < 65536); /* need to implement prescaler in this case */ if (temp > 2) { /* Round scaler up to nearest power of two */ temp = (temp * 2) - 1; for (i = 0, j = temp; j != 1; j >>= 1, i++) {}; ctar |= MCF_DSPI_DCTAR_ASC(i - 1); } else { ctar |= MCF_DSPI_DCTAR_ASC(0); } /* chip-select deassertion to chip-select assertion delay */ temp = (device->delay_cscs * (fbus / 1000)) / 1000000; ASSERT(temp < 65536); /* need to implement prescaler in this case */ if (temp > 2) { /* Round scaler up to nearest power of two */ temp = (temp * 2) - 1; for (i = 0, j = temp; j != 1; j >>= 1, i++) {}; ctar |= MCF_DSPI_DCTAR_DT(i - 1); } else { ctar |= MCF_DSPI_DCTAR_DT(0); } /* baud rate (assume PBR = 00 and DBR = 1; BR = fbus / baud ) */ temp = fbus / device->baud; ASSERT(temp < 65536); /* need to implement prescaler in this case */ if (temp > 2) { /* Round scaler up to nearest power of two */ temp = (temp * 2) - 1; for (i = 0, j = temp; j != 1; j >>= 1, i++) {}; ctar |= 0 | MCF_DSPI_DCTAR_DBR | MCF_DSPI_DCTAR_BR(i - 1); } else { ctar |= 0 | MCF_DSPI_DCTAR_DBR | MCF_DSPI_DCTAR_BR(0); } /* * Store the transfer attributes in the register corresponding to the CS * This isn't required, but done here to simplify the driver. */ MCF_DSPI_DCTAR(device->cs) = ctar;}/********************************************************************//*! * Write to SPI slave. * \param spi_device SPI device to communicate with * \param buffer Buffer holding data to be written * \param length Number of bytes to write * \param wait Wait for the command to complete? * \return Zero for success; Non-zero otherwise. * * Write the buffer to the specified SPI device. This will stall to wait for * the DSPI to be available if it is busy with another transfer */intspi_master_write(SPI_DEVICE *device, uint8 *tx_buf, int length){ SPI_MSG_CHAIN m; SPI_MSG_LINK l; memset(&m, 0, sizeof(SPI_MSG_CHAIN)); m.device = device; m.link = &l; memset(&l, 0, sizeof(SPI_MSG_LINK)); l.tx_buf = tx_buf; 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;}/********************************************************************//*! * Read from SPI slave. * \param spi_device SPI device to communicate with * \param buffer Buffer to hold read data * \param length Number of bytes to read * \return Zero for success; Non-zero otherwise. * * Read data from a SPI device into the receive buffer. This will stall to wait * for the DSPI to be available if it is busy with another transfer. */intspi_master_read(SPI_DEVICE *device, uint8 *rx_buf, int length){ SPI_MSG_CHAIN m; SPI_MSG_LINK l; memset(&m, 0, sizeof(SPI_MSG_CHAIN)); m.device = device; m.link = &l; memset(&l, 0, sizeof(SPI_MSG_LINK)); l.tx_buf = rx_buf; 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;}/********************************************************************//*! * Perform a synchronous, full duplex transfer to/from an SPI slave * \param dev SPI device to communicate with
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -