Skip to content

Commit ea510ce

Browse files
committed
Fixed three issues with the SPI driver for the LPC1549 platform:
* The TXDATCTL register was used even if only the control signals were modified which caused extra data to be transmitted. * The RXDAT register does not only contain the received data, but also control information in bits 16 to 20. The old code did not mask out the control information and in rare cases that would cause the returned data to include too much information (i.e. received 0xaa as data but the function returned 0x300aa). * The LPC1549 uses a Switch Matric (SWM) to allow any pin to have any function. This is not used in the old code which simply assigned the first instance of the SPI class to SPI0 and the second instance to SPI1. The third instance would result in a call to error(). This behaviour is not at all working with real world examples where the SPI bus contains more than two peripherals. The third peripheral would cause the platform to end up in error(). The solution is to modify the get_available_spi() function to first see if the MISO/MOSI/SCLK and SSEL pins are already configured for use as either SPI0 or SPI1. If the exact same pins are already used then the SPIx will be reused. If one or more pins are different then another SPIx will be used (or if both are alredy in use then error()). With this change it is now possible to do this: MyFlash f(D11,D12,D13); // Will use SPI0 MyTemp t(D11,D12,D13); // Will use SPI0 SDFileSystem s(D11,D12,D13,"sd"); // Will use SPI0 MyDisplay d(D11,D12,D13); // Will use SPI0 The old/existing code would have resulted in this MyFlash f(D11,D12,D13); // Will use SPI0 MyTemp t(D11,D12,D13); // Will use SPI1 SDFileSystem s(D11,D12,D13,"sd"); // error() MyDisplay d(D11,D12,D13); // Will never be called
1 parent 6663575 commit ea510ce

File tree

1 file changed

+68
-12
lines changed
  • libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC15XX

1 file changed

+68
-12
lines changed

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC15XX/spi_api.c

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,69 @@ static const SWM_Map SWM_SPI_MISO[] = {
4343

4444
// bit flags for used SPIs
4545
static unsigned char spi_used = 0;
46-
static int get_available_spi(void)
46+
static int get_available_spi(PinName mosi, PinName miso, PinName sclk, PinName ssel)
4747
{
48-
int i;
49-
for (i=0; i<2; i++) {
50-
if ((spi_used & (1 << i)) == 0)
51-
return i;
48+
if (spi_used == 0) {
49+
return 0; // The first user
5250
}
51+
52+
const SWM_Map *swm;
53+
uint32_t regVal;
54+
55+
// Investigate if same pins as the used SPI0/1 - to be able to reuse it
56+
for (int spi_n = 0; spi_n < 2; spi_n++) {
57+
if (spi_used & (1<<spi_n)) {
58+
if (sclk != NC) {
59+
swm = &SWM_SPI_SCLK[spi_n];
60+
regVal = LPC_SWM->PINASSIGN[swm->n] & (0xFF << swm->offset);
61+
if (regVal != (sclk << swm->offset)) {
62+
// Existing pin is not the same as the one we want
63+
continue;
64+
}
65+
}
66+
67+
if (mosi != NC) {
68+
swm = &SWM_SPI_MOSI[spi_n];
69+
regVal = LPC_SWM->PINASSIGN[swm->n] & (0xFF << swm->offset);
70+
if (regVal != (mosi << swm->offset)) {
71+
// Existing pin is not the same as the one we want
72+
continue;
73+
}
74+
}
75+
76+
if (miso != NC) {
77+
swm = &SWM_SPI_MISO[spi_n];
78+
regVal = LPC_SWM->PINASSIGN[swm->n] & (0xFF << swm->offset);
79+
if (regVal != (miso << swm->offset)) {
80+
// Existing pin is not the same as the one we want
81+
continue;
82+
}
83+
}
84+
85+
if (ssel != NC) {
86+
swm = &SWM_SPI_SSEL[spi_n];
87+
regVal = LPC_SWM->PINASSIGN[swm->n] & (0xFF << swm->offset);
88+
if (regVal != (ssel << swm->offset)) {
89+
// Existing pin is not the same as the one we want
90+
continue;
91+
}
92+
}
93+
94+
// The pins for the currently used SPIx are the same as the
95+
// ones we want so we will reuse it
96+
return spi_n;
97+
}
98+
}
99+
100+
// None of the existing SPIx pin setups match the pins we want
101+
// so the last hope is to select one unused SPIx
102+
if ((spi_used & 1) == 0) {
103+
return 0;
104+
} else if ((spi_used & 2) == 0) {
105+
return 1;
106+
}
107+
108+
// No matching setup and no free SPIx
53109
return -1;
54110
}
55111

@@ -58,7 +114,7 @@ static inline void spi_enable(spi_t *obj);
58114

59115
void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
60116
{
61-
int spi_n = get_available_spi();
117+
int spi_n = get_available_spi(mosi, miso, sclk, ssel);
62118
if (spi_n == -1) {
63119
error("No available SPI");
64120
}
@@ -138,10 +194,10 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
138194
obj->spi->CFG = tmp;
139195

140196
// select frame length
141-
tmp = obj->spi->TXDATCTL;
197+
tmp = obj->spi->TXCTL;
142198
tmp &= ~(0xf << 24);
143199
tmp |= (LEN << 24);
144-
obj->spi->TXDATCTL = tmp;
200+
obj->spi->TXCTL = tmp;
145201

146202
spi_enable(obj);
147203
}
@@ -181,14 +237,14 @@ static inline void spi_write(spi_t *obj, int value)
181237
{
182238
while (!spi_writeable(obj));
183239
// end of transfer
184-
obj->spi->TXDATCTL |= (1 << 20);
185-
obj->spi->TXDAT = value;
240+
obj->spi->TXCTL |= (1 << 20);
241+
obj->spi->TXDAT = (value & 0xffff);
186242
}
187243

188244
static inline int spi_read(spi_t *obj)
189245
{
190246
while (!spi_readable(obj));
191-
return obj->spi->RXDAT;
247+
return obj->spi->RXDAT & 0xffff; // Only the lower 16 bits contain data
192248
}
193249

194250
int spi_busy(spi_t *obj)
@@ -210,7 +266,7 @@ int spi_slave_receive(spi_t *obj)
210266

211267
int spi_slave_read(spi_t *obj)
212268
{
213-
return obj->spi->RXDAT;
269+
return obj->spi->RXDAT & 0xffff; // Only the lower 16 bits contain data
214270
}
215271

216272
void spi_slave_write(spi_t *obj, int value)

0 commit comments

Comments
 (0)