X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Fcortex-m3%2Fdrv%2Fssi_lm3s.c;h=8d314dbe3720ccd147843d1af9b6ae36a5d72a18;hb=666f80bddb3d83383dee8f572b626690e81e3b18;hp=f67f1a1cbc37cb28c73ac16ef33ba23e577f2088;hpb=dc8158b1e365c04ab3cbb198cbcac6cc5bdedb87;p=bertos.git diff --git a/bertos/cpu/cortex-m3/drv/ssi_lm3s.c b/bertos/cpu/cortex-m3/drv/ssi_lm3s.c index f67f1a1c..8d314dbe 100644 --- a/bertos/cpu/cortex-m3/drv/ssi_lm3s.c +++ b/bertos/cpu/cortex-m3/drv/ssi_lm3s.c @@ -35,13 +35,16 @@ * \author Andrea Righi */ + +#include "ssi_lm3s.h" + #include #include -#include "io/lm3s.h" -#include "drv/ssi_lm3s.h" + +#include /* memset() */ /* SSI clocking informations (CPSDVSR + SCR) */ -struct ssi_clock +struct SSIClock { unsigned int cpsdvsr; unsigned int scr; @@ -50,10 +53,10 @@ struct ssi_clock /* * Evaluate the SSI clock prescale (SSICPSR) and SSI serial clock rate (SCR). */ -INLINE struct ssi_clock -lm3s_ssi_prescale(unsigned int bitrate) +INLINE struct SSIClock +lm3s_ssiPrescale(unsigned int bitrate) { - struct ssi_clock ret; + struct SSIClock ret; for (ret.cpsdvsr = 2, ret.scr = CPU_FREQ / bitrate / ret.cpsdvsr - 1; ret.scr > 255; ret.cpsdvsr += 2); @@ -65,133 +68,141 @@ lm3s_ssi_prescale(unsigned int bitrate) /* * Initialize the SSI interface. * - * @base: the SSI port base address. - * @frame: the data transfer protocol (SSI_FRF_MOTO_MODE_0, - * SSI_FRF_MOTO_MODE_1, SSI_FRF_MOTO_MODE_2, SSI_FRF_MOTO_MODE_3, SSI_FRF_TI or - * SSI_FRF_NMW) - * @mode: the mode of operation (SSI_MODE_MASTER, SSI_MODE_SLAVE, - * SSI_MODE_SLAVE_OD) - * @bitrate: the SSI clock rate - * @data_width: number of bits per frame - * * Return 0 in case of success, a negative value otherwise. */ -int lm3s_ssi_init(uint32_t base, uint32_t frame, int mode, - unsigned int bitrate, unsigned int data_width) +int lm3s_ssiOpen(uint32_t addr, uint32_t frame, int mode, + int bitrate, uint32_t data_width) { - struct ssi_clock ssi_clock; + struct SSIClock ssi_clock; - ASSERT(base == SSI0_BASE || base == SSI1_BASE); + ASSERT(addr == SSI0_BASE || addr == SSI1_BASE); /* Configure the SSI operating mode */ switch (mode) { /* SSI Slave Mode Output Disable */ case SSI_MODE_SLAVE_OD: - HWREG(base + SSI_O_CR1) = SSI_CR1_SOD; + HWREG(addr + SSI_O_CR1) = SSI_CR1_SOD; break; /* SSI Slave */ case SSI_MODE_SLAVE: - HWREG(base + SSI_O_CR1) = SSI_CR1_MS; + HWREG(addr + SSI_O_CR1) = SSI_CR1_MS; break; /* SSI Master */ case SSI_MODE_MASTER: - HWREG(base + SSI_O_CR1) = 0; + HWREG(addr + SSI_O_CR1) = 0; break; default: ASSERT(0); return -1; } /* Configure the peripheral clock and frame format */ - ssi_clock = lm3s_ssi_prescale(bitrate); - HWREG(base + SSI_O_CPSR) = ssi_clock.cpsdvsr; - HWREG(base + SSI_O_CR0) = - (ssi_clock.scr << 8) | - ((frame & 3) << 6) | - (frame & SSI_CR0_FRF_M) | + ssi_clock = lm3s_ssiPrescale(bitrate); + HWREG(addr + SSI_O_CPSR) = ssi_clock.cpsdvsr; + HWREG(addr + SSI_O_CR0) = + (ssi_clock.scr << 8) | + ((frame & 3) << 6) | + (frame & SSI_CR0_FRF_M) | (data_width - 1); - return 0; -} + /* Enable the SSI interface */ + HWREG(addr + SSI_O_CR1) |= SSI_CR1_SSE; -/* Enable the SSI interface */ -void lm3s_ssi_enable(uint32_t base) -{ - HWREG(base + SSI_O_CR1) |= SSI_CR1_SSE; -} - -/* Disable the SSI interface */ -void lm3s_ssi_disable(uint32_t base) -{ - HWREG(base + SSI_O_CR1) &= ~SSI_CR1_SSE; + return 0; } /* - * Put a frame into the SSI transmit FIFO. + * Write data to the SSI bus. * - * NOTE: the upper bits of the frame will be automatically discarded by the - * hardware according to the frame data width, configured by lm3s_ssi_init(). + * Return the number of bytes written to the bus. */ -void lm3s_ssi_write_frame(uint32_t base, uint32_t val) +static size_t lm3s_ssiWrite(struct KFile *fd, const void *buf, size_t size) { - /* Wait for available space in the TX FIFO */ - while (!(HWREG(base + SSI_O_SR) & SSI_SR_TNF)) - cpu_relax(); - /* Enqueue data to the TX FIFO */ - HWREG(base + SSI_O_DR) = val; + LM3SSSI *fds = LM3SSSI_CAST(fd); + const char *p = (const char *)buf; + uint32_t frame; + size_t count = 0; + + while (count < size) + { + frame = p[count]; + if (fds->flags & LM3S_SSI_NONBLOCK) + { + if (!lm3s_ssiWriteFrameNonBlocking(fds->addr, + frame)) + break; + } + else + lm3s_ssiWriteFrame(fds->addr, frame); + count++; + } + return count; } /* - * Put a frame into the SSI transmit FIFO without blocking. - * - * NOTE: the upper bits of the frame will be automatically discarded by the - * hardware according to the frame data width, configured by lm3s_ssi_init(). + * Read data from the SSI bus. * - * Return the number of frames written to the TX FIFO. + * Return the number of bytes read from the bus. */ -int lm3s_ssi_write_frame_nonblocking(uint32_t base, uint32_t val) +static size_t lm3s_ssiRead(struct KFile *fd, void *buf, size_t size) { - /* Check for available space in the TX FIFO */ - if (!(HWREG(base + SSI_O_SR) & SSI_SR_TNF)) - return 0; - /* Enqueue data to the TX FIFO */ - HWREG(base + SSI_O_DR) = val; - return 1; + LM3SSSI *fds = LM3SSSI_CAST(fd); + + uint8_t *p = (uint8_t *)buf; + uint32_t frame; + size_t count = 0; + + while (count < size) + { + if (fds->flags & LM3S_SSI_NONBLOCK) + { + if (!lm3s_ssiReadFrameNonBlocking(fds->addr, &frame)) + break; + } + else + lm3s_ssiReadFrame(fds->addr, &frame); + *p++ = (uint8_t)frame; + count++; + } + return count; } -/* - * Get a frame from the SSI receive FIFO. - */ -void lm3s_ssi_read_frame(uint32_t base, uint32_t *val) + +/* Wait for data in the TX FIFO being actually transmitted */ +static int lm3s_ssiFlush(struct KFile *fd) { - /* Wait for data available in the RX FIFO */ - while (!(HWREG(base + SSI_O_SR) & SSI_SR_RNE)) + LM3SSSI *fds = LM3SSSI_CAST(fd); + + while (!lm3s_ssiTxDone(fds->addr)) cpu_relax(); - /* Read data from SSI RX FIFO */ - *val = HWREG(base + SSI_O_DR); + return 0; } -/* - * Get a frame into the SSI receive FIFO without blocking. - * - * Return the number of frames read from the RX FIFO. - */ -int lm3s_ssi_read_frame_nonblocking(uint32_t base, uint32_t *val) +/* Disable the SSI interface */ +static int lm3s_ssiClose(struct KFile *fd) { - /* Check for data available in the RX FIFO */ - if (!(HWREG(base + SSI_O_SR) & SSI_SR_RNE)) - return 0; - /* Read data from SSI RX FIFO */ - *val = HWREG(base + SSI_O_DR); - return 1; + LM3SSSI *fds = LM3SSSI_CAST(fd); + + lm3s_ssiFlush(fd); + HWREG(fds->addr + SSI_O_CR1) &= ~SSI_CR1_SSE; + return 0; } -/* - * Check if the SSI transmitter is busy or not - * - * This allows to determine whether the TX FIFO have been cleared by the - * hardware, so the transmission can be safely considered completed. +/** + * Initialize a LM3S SSI driver. */ -bool lm3s_ssi_txdone(uint32_t base) +void lm3s_ssiInit(struct LM3SSSI *fds, uint32_t addr, uint32_t frame, int mode, + int bitrate, uint32_t data_width) { - /* Check if the SSI is busy */ - return (HWREG(base + SSI_O_SR) & SSI_SR_BSY) ? true : false; + memset(fds, 0, sizeof(*fds)); + DB(fds->fd._type = KFT_LM3SSSI); + + /* TODO: only 8-bit frame size is supported */ + ASSERT(data_width == 8); + + fds->fd.write = lm3s_ssiWrite; + fds->fd.read = lm3s_ssiRead; + fds->fd.close = lm3s_ssiClose; + fds->fd.flush = lm3s_ssiFlush; + + fds->addr = addr; + lm3s_ssiOpen(addr, frame, mode, bitrate, data_width); }