I’ve been using the SPI peripheral for a few odds and sods, but I’m now encountering a slave device which requires 12-bit long data frames and I’m not entirely clear how that should be done. I set up my SPI registers:
SPI_REG(SPI_REG_FMT) =
SPI_FMT_PROTO(SPI_PROTO_S) |
SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) |
SPI_FMT_DIR(SPI_DIR_TX) |
SPI_FMT_LEN(12); // 12 bit long packets
SPI_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
How do I send out the remaining nibble? If I try writing to the FIFO again it triggers a new frame automatically so I see my data byte as part of one 12-bit frame (padded with 1s) for the first frame, followed by a second frame with my nibble.
For the Freedom E310, the maximum SPI frame length is 8 (although the Chisel RTL is parameterized to support an arbitrary length).
However, it is possible to emulate a 12-bit transfer using two consecutive 8-bit “frames”. Assuming that the slave is able to tolerate the extra 4 data bits:
Otherwise, to send exactly 12 bits, use an 8-bit frame followed by a 4-bit frame. Note that it is necessary to wait for all ongoing transfers to complete before changing the frame length.
// disable watermark interrupts (default on reset)
SPI_REG(SPI_REG_IE) = 0;
// set watermark to detect empty TXFIFO (default on reset)
SPI_REG(SPI_REG_TXCTRL) = SPI_TXWM(0);
static void fmt(unsigned int len)
{
SPI_REG(SPI_REG_FMT) =
SPI_FMT_PROTO(SPI_PROTO_S) |
SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) |
SPI_FMT_DIR(SPI_DIR_TX) |
SPI_FMT_LEN(len);
}
void write_SPI(uint16_t data)
{
SPI_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; // assert CS
while (!(SPI_REG(SPI_REG_IP) & SPI_IP_TXWM)); // wait for TXFIFO to drain
fmt(8); // set frame length to 8
tx(data >> 4); // send upper 8 bits
while (!(SPI_REG(SPI_REG_IP) & SPI_IP_TXWM)); // wait for TXFIFO to drain
fmt(4); // set frame length to 4
tx(data << 4); // send lower 4 bits (right-aligned when using MSB-first order)
SPI_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; // deassert CS
}
Thanks for the feedback and code samples. I gave it a try and switching format helps in that it does reduce the MOSI output to the desired 12 bits. However, even with using CSMODE as above it still de-asserts the CS in between frames (see attached capture). I had to leave the office before I had a chance to try, but I’ll try and control that pin manually via GPIO_REG instead.