Skip to content

Commit

Permalink
LPC1768: Fix SPI 16-bit transfers (#277)
Browse files Browse the repository at this point in the history
* LPC1768: Fix I2C pins not being open drain, fix destroying and recreating I2C making transactions fail

* bus -> peripheral

* LPC1768: Support static pinmaps

* Update ARCH_PRO pin names header to pass muster

* LPC1768: Fix SPI 16-bit transfers

* Fix merge mistake
  • Loading branch information
multiplemonomials authored May 7, 2024
1 parent 94a7fbc commit 1b60dda
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 13 deletions.
1 change: 1 addition & 0 deletions targets/TARGET_NXP/TARGET_LPC176X/PeripheralNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ typedef enum {

// Note: We only use the two SSP peripherals in Mbed, not SPI0. This is because
// SPI0 is a legacy version of the SSP peripheral and cannot be used at the same time as SSP0.
#define DEVICE_SPI_COUNT 2
typedef enum {
SPI_0 = (int)LPC_SSP0_BASE,
SPI_1 = (int)LPC_SSP1_BASE
Expand Down
1 change: 1 addition & 0 deletions targets/TARGET_NXP/TARGET_LPC176X/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ struct i2c_s {

struct spi_s {
LPC_SSP_TypeDef *spi;
uint8_t bits_per_word;
};

struct flash_s {
Expand Down
61 changes: 48 additions & 13 deletions targets/TARGET_NXP/TARGET_LPC176X/spi_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ void spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) {
}
}

SPIName spi_get_peripheral_name(PinName mosi, PinName miso, PinName sclk)
{
SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
SPIName spi_periph = (SPIName)pinmap_merge(spi_sclk, spi_data);
return spi_periph;
}

void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
spi_pinmap_t pinmap;
pinmap.mosi_pin = mosi;
Expand All @@ -56,14 +66,10 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
pinmap.ssel_pin = ssel;

// determine the SPI to use
SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
pinmap.peripheral = pinmap_merge(spi_data, spi_cntl);
MBED_ASSERT((int)obj->spi != NC);
SPIName spi_mosi_miso_sclk_periph = spi_get_peripheral_name(mosi, miso, sclk);
SPIName spi_ssel_periph = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
pinmap.peripheral = pinmap_merge(spi_mosi_miso_sclk_periph, spi_ssel_periph);
MBED_ASSERT(pinmap.peripheral != NC);

// Get pin functions
pinmap.mosi_function = pinmap_find_function(mosi, PinMap_SPI_MOSI);
Expand All @@ -80,6 +86,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) {
ssp_disable(obj);
MBED_ASSERT(((bits >= 4) && (bits <= 16)) && (mode >= 0 && mode <= 3));

obj->bits_per_word = bits;
int polarity = (mode & 0x2) ? 1 : 0;
int phase = (mode & 0x1) ? 1 : 0;

Expand Down Expand Up @@ -186,11 +193,39 @@ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
char *rx_buffer, int rx_length, char write_fill) {
int total = (tx_length > rx_length) ? tx_length : rx_length;

for (int i = 0; i < total; i++) {
char out = (i < tx_length) ? tx_buffer[i] : write_fill;
char in = spi_master_write(obj, out);
if (i < rx_length) {
rx_buffer[i] = in;
if(obj->bits_per_word > 8) {
// 2 bytes per write/read operation
MBED_ASSERT(tx_length % 2 == 0);
MBED_ASSERT(rx_length % 2 == 0);

// Extend write fill value to 16 bits
const uint16_t write_fill_u16 = (((uint16_t)write_fill) << 8) | write_fill;

// Access input and output arrays as 16-bit words.
// This might do unaligned access, but that's OK for integers on Cortex-M3
uint16_t const * const tx_buffer_u16 = (uint16_t const *)tx_buffer;
uint16_t * const rx_buffer_u16 = (uint16_t *)rx_buffer;

const int tx_length_u16 = tx_length / 2;
const int rx_length_u16 = rx_length / 2;

for (int i = 0; i < total / 2; i++) {
uint16_t out = (i < tx_length_u16) ? tx_buffer_u16[i] : write_fill_u16;
uint16_t in = spi_master_write(obj, out);
if (i < rx_length_u16) {
rx_buffer_u16[i] = in;
printf("rx_buffer_u16[%d] <= 0x%hx\n", i, in);
}
}
}
else {
// 1 byte per read/write operation
for (int i = 0; i < total; i++) {
uint16_t out = (i < tx_length) ? tx_buffer[i] : write_fill;
uint16_t in = spi_master_write(obj, out);
if (i < rx_length) {
rx_buffer[i] = in;
}
}
}

Expand Down

0 comments on commit 1b60dda

Please sign in to comment.