From 4292adebc1d3a4d554aaabf1f1fe584a62e4a9a6 Mon Sep 17 00:00:00 2001 From: samux Date: Wed, 8 May 2013 16:05:57 +0100 Subject: [PATCH] [KL25Z]: spi slave and i2c slave support --- .../mbed/vendor/Freescale/capi/KL25Z/device.h | 4 +- .../mbed/vendor/Freescale/capi/i2c_api.c | 183 +++++++++++++++--- .../mbed/vendor/Freescale/capi/spi_api.c | 26 ++- libraries/tests/mbed/i2c_master/main.cpp | 41 ++++ libraries/tests/mbed/i2c_slave/main.cpp | 31 +++ libraries/tests/mbed/spi_master/main.cpp | 29 +++ libraries/tests/mbed/spi_slave/main.cpp | 21 ++ workspace_tools/tests.py | 26 ++- 8 files changed, 329 insertions(+), 32 deletions(-) create mode 100644 libraries/tests/mbed/i2c_master/main.cpp create mode 100644 libraries/tests/mbed/i2c_slave/main.cpp create mode 100644 libraries/tests/mbed/spi_master/main.cpp create mode 100644 libraries/tests/mbed/spi_slave/main.cpp diff --git a/libraries/mbed/vendor/Freescale/capi/KL25Z/device.h b/libraries/mbed/vendor/Freescale/capi/KL25Z/device.h index 9c2e33db29..82374a0224 100644 --- a/libraries/mbed/vendor/Freescale/capi/KL25Z/device.h +++ b/libraries/mbed/vendor/Freescale/capi/KL25Z/device.h @@ -28,10 +28,10 @@ #define DEVICE_SERIAL 1 #define DEVICE_I2C 1 -#define DEVICE_I2CSLAVE 0 +#define DEVICE_I2CSLAVE 1 #define DEVICE_SPI 1 -#define DEVICE_SPISLAVE 0 +#define DEVICE_SPISLAVE 1 #define DEVICE_CAN 0 diff --git a/libraries/mbed/vendor/Freescale/capi/i2c_api.c b/libraries/mbed/vendor/Freescale/capi/i2c_api.c index d6385f2d41..c7feee8bc8 100644 --- a/libraries/mbed/vendor/Freescale/capi/i2c_api.c +++ b/libraries/mbed/vendor/Freescale/capi/i2c_api.c @@ -37,7 +37,7 @@ static const PinMap PinMap_I2C_SCL[] = { {NC , NC, 0} }; -const uint32_t ICR[0x40] = { +static const uint16_t ICR[0x40] = { 20, 22, 24, 26, 28, 30, 34, 40, 28, 32, 36, 40, 44, 48, 56, @@ -53,6 +53,8 @@ const uint32_t ICR[0x40] = { 2304, 2560, 3072, 3840 }; +static uint8_t first_read; + void i2c_init(i2c_t *obj, PinName sda, PinName scl) { // determine the I2C to use @@ -77,6 +79,8 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) { pinmap_pinout(sda, PinMap_I2C_SDA); pinmap_pinout(scl, PinMap_I2C_SCL); + + first_read = 1; } int i2c_start(i2c_t *obj) { @@ -88,6 +92,7 @@ int i2c_start(i2c_t *obj) { obj->i2c->C1 |= I2C_C1_MST_MASK; obj->i2c->C1 |= I2C_C1_TX_MASK; } + first_read = 1; return 0; } @@ -101,15 +106,37 @@ void i2c_stop(i2c_t *obj) { // This wait is also included on the samples // code provided with the freedom board for (n = 0; n < 100; n++) __NOP(); + first_read = 1; +} + +static int timeout_status_poll(i2c_t *obj, uint32_t mask) { + uint32_t i, timeout = 1000; + + for (i = 0; i < timeout; i++) { + if (obj->i2c->S & mask) + return 0; + } + + return 1; } // this function waits the end of a tx transfer and return the status of the transaction: -// 0: OK -// 1: failure +// 0: OK ack received +// 1: OK ack not received +// 2: failure static int i2c_wait_end_tx_transfer(i2c_t *obj) { - // wait for the end of the tx transfer - while((obj->i2c->S & I2C_S_IICIF_MASK) == 0); + + // wait for the interrupt flag + if (timeout_status_poll(obj, I2C_S_IICIF_MASK)) { + return 2; + } + obj->i2c->S |= I2C_S_IICIF_MASK; + + // wait transfer complete + if (timeout_status_poll(obj, I2C_S_TCF_MASK)) { + return 2; + } // check if we received the ACK or not return obj->i2c->S & I2C_S_RXAK_MASK ? 1 : 0; @@ -120,8 +147,12 @@ static int i2c_wait_end_tx_transfer(i2c_t *obj) { // 1: failure static int i2c_wait_end_rx_transfer(i2c_t *obj) { // wait for the end of the rx transfer - while((obj->i2c->S & I2C_S_IICIF_MASK) == 0); + if (timeout_status_poll(obj, I2C_S_IICIF_MASK)) { + return 1; + } + obj->i2c->S |= I2C_S_IICIF_MASK; + return 0; } @@ -164,7 +195,7 @@ void i2c_frequency(i2c_t *obj, int hz) { uint32_t PCLK = 24000000u; uint32_t pulse = PCLK / (hz * 2); - // we look for the value that minimize the error + // we look for the values that minimize the error // test all the MULT values for (i = 1; i < 5; i*=2) { @@ -185,9 +216,8 @@ void i2c_frequency(i2c_t *obj, int hz) { } int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { - int count; - char * ptr; - char dummy_read; + uint8_t count; + char dummy_read, *ptr; if (i2c_start(obj)) { i2c_stop(obj); @@ -202,33 +232,26 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { // set rx mode obj->i2c->C1 &= ~I2C_C1_TX_MASK; - // Read in all except last byte - for (count = 0; count < (length - 1); count++) { + // Read in bytes + for (count = 0; count < (length); count++) { ptr = (count == 0) ? &dummy_read : &data[count - 1]; - if (i2c_do_read(obj, ptr, 0)) { + uint8_t stop_ = (count == (length - 1)) ? 1 : 0; + if (i2c_do_read(obj, ptr, stop_)) { i2c_stop(obj); return 1; } } - // read in last byte - ptr = (count == 0) ? &dummy_read : &data[count - 1]; - if (i2c_do_read(obj, ptr, 1)) { - i2c_stop(obj); - return 1; - } - // If not repeated start, send stop. if (stop) { i2c_stop(obj); } // last read - data[count] = obj->i2c->D; + data[count-1] = obj->i2c->D; return 0; } - int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { int i; @@ -237,12 +260,12 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { return 1; } - if (i2c_do_write(obj, (address & 0xFE) )) { + if (i2c_do_write(obj, (address & 0xFE))) { i2c_stop(obj); return 1; } - for (i=0; ii2c->C1 &= ~I2C_C1_TX_MASK; + + if(first_read) { + // first dummy read + i2c_do_read(obj, &data, 0); + first_read = 0; + } + + if (last) { + // set tx mode + obj->i2c->C1 |= I2C_C1_TX_MASK; + return obj->i2c->D; + } + i2c_do_read(obj, &data, last); + return data; } int i2c_byte_write(i2c_t *obj, int data) { + first_read = 1; + + // set tx mode + obj->i2c->C1 |= I2C_C1_TX_MASK; + return !i2c_do_write(obj, (data & 0xFF)); } + + +#if DEVICE_I2CSLAVE +void i2c_slave_mode(i2c_t *obj, int enable_slave) { + if (enable_slave) { + // set slave mode + obj->i2c->C1 &= ~I2C_C1_MST_MASK; + obj->i2c->C1 |= I2C_C1_IICIE_MASK; + } else { + // set master mode + obj->i2c->C1 |= I2C_C1_MST_MASK; + } +} + +int i2c_slave_receive(i2c_t *obj) { + switch(obj->i2c->S) { + // read addressed + case 0xE6: return 1; + + // write addressed + case 0xE2: return 3; + + default: return 0; + } +} + +int i2c_slave_read(i2c_t *obj, char *data, int length) { + uint8_t dummy_read, count; + uint8_t * ptr; + + // set rx mode + obj->i2c->C1 &= ~I2C_C1_TX_MASK; + + // first dummy read + dummy_read = obj->i2c->D; + if(i2c_wait_end_rx_transfer(obj)) { + return 0; + } + + // read address + dummy_read = obj->i2c->D; + if(i2c_wait_end_rx_transfer(obj)) { + return 0; + } + + // read (length - 1) bytes + for (count = 0; count < (length - 1); count++) { + data[count] = obj->i2c->D; + if(i2c_wait_end_rx_transfer(obj)) { + return 0; + } + } + + // read last byte + ptr = (length == 0) ? &dummy_read : (uint8_t *)&data[count]; + *ptr = obj->i2c->D; + + return (length) ? (count + 1) : 0; +} + +int i2c_slave_write(i2c_t *obj, const char *data, int length) { + uint32_t i, count = 0; + + // set tx mode + obj->i2c->C1 |= I2C_C1_TX_MASK; + + for (i = 0; i < length; i++) { + if(i2c_do_write(obj, data[count++]) == 2) { + return 0; + } + } + + // set rx mode + obj->i2c->C1 &= ~I2C_C1_TX_MASK; + + // dummy rx transfer needed + // otherwise the master cannot generate a stop bit + obj->i2c->D; + if(i2c_wait_end_rx_transfer(obj) == 2) { + return 0; + } + + return count; +} + +void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) { + obj->i2c->A1 = address & 0xfe; +} +#endif + diff --git a/libraries/mbed/vendor/Freescale/capi/spi_api.c b/libraries/mbed/vendor/Freescale/capi/spi_api.c index d610ab5441..71ea938491 100644 --- a/libraries/mbed/vendor/Freescale/capi/spi_api.c +++ b/libraries/mbed/vendor/Freescale/capi/spi_api.c @@ -103,7 +103,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) { uint8_t polarity = (mode & 0x2) ? 1 : 0; uint8_t phase = (mode & 0x1) ? 1 : 0; - uint8_t c1_data = ((!slave) << 4) | (polarity << 3) | (phase << 3); + uint8_t c1_data = ((!slave) << 4) | (polarity << 3) | (phase << 2); // clear MSTR, CPOL and CPHA bits obj->spi->C1 &= ~(0x7 << 2); @@ -143,17 +143,33 @@ void spi_frequency(spi_t *obj, int hz) { obj->spi->BR = ((ref_prescaler & 0x7) << 4) | (ref_spr & 0xf); } +static inline int spi_writeable(spi_t * obj) { + return (obj->spi->S & SPI_S_SPTEF_MASK) ? 1 : 0; +} + +static inline int spi_readable(spi_t * obj) { + return (obj->spi->S & SPI_S_SPRF_MASK) ? 1 : 0; +} int spi_master_write(spi_t *obj, int value) { // wait tx buffer empty - while((obj->spi->S & SPI_S_SPTEF_MASK) == 0); + while(!spi_writeable(obj)); obj->spi->D = (value & 0xff); // wait rx buffer full - while ((obj->spi->S & SPI_S_SPRF_MASK) == 0); + while (!spi_readable(obj)); return obj->spi->D & 0xff; } -int spi_busy(spi_t *obj) { - return -1; +int spi_slave_receive(spi_t *obj) { + return spi_readable(obj); +} + +int spi_slave_read(spi_t *obj) { + return obj->spi->D; +} + +void spi_slave_write(spi_t *obj, int value) { + while (!spi_writeable(obj)); + obj->spi->D = value; } diff --git a/libraries/tests/mbed/i2c_master/main.cpp b/libraries/tests/mbed/i2c_master/main.cpp new file mode 100644 index 0000000000..3c17c70756 --- /dev/null +++ b/libraries/tests/mbed/i2c_master/main.cpp @@ -0,0 +1,41 @@ +#include "mbed.h" +#include "test_env.h" + +#define SIZE (10) +#define ADDR (0x90) + +#if defined(TARGET_KL25Z) +I2C i2c(PTE0, PTE1); +#else +I2C i2c(p28, p27); +#endif + +int main() { + bool success = true; + char buf[] = {3, 2, 1, 4, 5, 6, 7, 8, 9, 10}; + char res[SIZE]; + + i2c.write(ADDR, buf, SIZE); + i2c.read(ADDR, res, SIZE); + + // here should be buf[all]++ + i2c.write(ADDR, res, SIZE); + i2c.read(ADDR, res, SIZE); + + // here should be buf[all]+=2 + i2c.write(ADDR, res, SIZE); + i2c.write(ADDR, res, SIZE); + + // here should be buf[all]+=3 + i2c.read(ADDR, res, SIZE); + i2c.read(ADDR, res, SIZE); + + for(int i = 0; i < SIZE; i++) { + if (res[i] != (buf[i] + 3)) { + success = false; + break; + } + } + + notify_completion(success); +} diff --git a/libraries/tests/mbed/i2c_slave/main.cpp b/libraries/tests/mbed/i2c_slave/main.cpp new file mode 100644 index 0000000000..1482d0a96e --- /dev/null +++ b/libraries/tests/mbed/i2c_slave/main.cpp @@ -0,0 +1,31 @@ +#include "mbed.h" +#include "test_env.h" + +#define SIZE (10) +#define ADDR (0x90) + +#if defined(TARGET_KL25Z) +I2CSlave slave(PTE0, PTE1); +#else +I2CSlave slave(p28, p27); +#endif + + int main() { + char buf[SIZE]; + + slave.address(ADDR); + + while (1) { + int i = slave.receive(); + switch (i) { + case I2CSlave::ReadAddressed: + slave.write(buf, SIZE); + break; + case I2CSlave::WriteAddressed: + slave.read(buf, SIZE); + for(int i = 0; i < SIZE; i++) + buf[i]++; + break; + } + } + } diff --git a/libraries/tests/mbed/spi_master/main.cpp b/libraries/tests/mbed/spi_master/main.cpp new file mode 100644 index 0000000000..1aed96af33 --- /dev/null +++ b/libraries/tests/mbed/spi_master/main.cpp @@ -0,0 +1,29 @@ +#include "mbed.h" +#include "test_env.h" + +#if defined(TARGET_KL25Z) +SPI spi(PTD2, PTD3, PTD1); // mosi, miso, sclk +DigitalOut cs(PTA13); +#else +SPI spi(p5, p6, p7); // mosi, miso, sclk +DigitalOut cs(p8); +#endif + +int main() { + int data = 0; + int res = 0; + + for(int i = 0; i < 30; i++) { + + cs = 0; + res = spi.write(data++); + cs = 1; + + wait_ms(0.001); + + if ((i > 1) && ((res + 2) != data)) + notify_completion(false); + } + + notify_completion(true); +} diff --git a/libraries/tests/mbed/spi_slave/main.cpp b/libraries/tests/mbed/spi_slave/main.cpp new file mode 100644 index 0000000000..1815102338 --- /dev/null +++ b/libraries/tests/mbed/spi_slave/main.cpp @@ -0,0 +1,21 @@ +#include "mbed.h" + +#if defined(TARGET_KL25Z) +SPISlave device(PTD2, PTD3, PTD1, PTD0); // mosi, miso, sclk, ssel +#else +SPISlave device(p5, p6, p7, p8); // mosi, miso, sclk, ssel +#endif + + +int main() { + uint8_t resp = 0; + + device.reply(resp); // Prime SPI with first reply + + while(1) { + if(device.receive()) { + resp = device.read(); // Read byte from master and add 1 + device.reply(resp); // Make this the next reply + } + } +} diff --git a/workspace_tools/tests.py b/workspace_tools/tests.py index ba078408f2..5db45eefb5 100644 --- a/workspace_tools/tests.py +++ b/workspace_tools/tests.py @@ -135,7 +135,31 @@ TESTS = [ "automated": True, "peripherals": ["MMA7660"] }, - + { + "id": "MBED_A14", "description": "MBED: I2C Master", + "source_dir": join(TEST_DIR, "mbed", "i2c_master"), + "dependencies": [MBED_LIBRARIES, TEST_MBED_LIB,], + "automated": True + }, + { + "id": "MBED_A15", "description": "MBED: I2C Slave", + "source_dir": join(TEST_DIR, "mbed", "i2c_slave"), + "dependencies": [MBED_LIBRARIES, TEST_MBED_LIB,], + "automated": True + }, + { + "id": "MBED_A16", "description": "MBED: SPI Master", + "source_dir": join(TEST_DIR, "mbed", "spi_master"), + "dependencies": [MBED_LIBRARIES, TEST_MBED_LIB,], + "automated": True + }, + { + "id": "MBED_A17", "description": "MBED: SPI Slave", + "source_dir": join(TEST_DIR, "mbed", "spi_slave"), + "dependencies": [MBED_LIBRARIES, TEST_MBED_LIB,], + "automated": True + }, + # Size benchmarks { "id": "BENCHMARK_1", "description": "Benchmark: Size (c environment)",