mbed library sources
Fork of mbed-src by
Revision 509:53fc1beb5664, committed 2015-04-09
- Comitter:
- mbed_official
- Date:
- Thu Apr 09 07:00:08 2015 +0100
- Parent:
- 508:4f5903e025e6
- Child:
- 510:bb3effbb3493
- Commit message:
- Synchronized with git revision c3cd171fc3a484f24e3c7fa3c25928ad3024a341
Full URL: https://github.com/mbedmicro/mbed/commit/c3cd171fc3a484f24e3c7fa3c25928ad3024a341/
LPC82X - Fixed hardcoded MRT_Clock_MHz
Changed in this revision
--- a/targets/hal/TARGET_NXP/TARGET_LPC82X/TARGET_LPC824/device.h Thu Apr 09 06:45:08 2015 +0100 +++ b/targets/hal/TARGET_NXP/TARGET_LPC82X/TARGET_LPC824/device.h Thu Apr 09 07:00:08 2015 +0100 @@ -29,7 +29,7 @@ #define DEVICE_SERIAL_FC 0 #define DEVICE_I2C 1 -#define DEVICE_I2CSLAVE 0 +#define DEVICE_I2CSLAVE 1 #define DEVICE_SPI 1 #define DEVICE_SPISLAVE 1
--- a/targets/hal/TARGET_NXP/TARGET_LPC82X/TARGET_SSCI824/device.h Thu Apr 09 06:45:08 2015 +0100 +++ b/targets/hal/TARGET_NXP/TARGET_LPC82X/TARGET_SSCI824/device.h Thu Apr 09 07:00:08 2015 +0100 @@ -29,7 +29,7 @@ #define DEVICE_SERIAL_FC 0 #define DEVICE_I2C 1 -#define DEVICE_I2CSLAVE 0 +#define DEVICE_I2CSLAVE 1 #define DEVICE_SPI 1 #define DEVICE_SPISLAVE 1
--- a/targets/hal/TARGET_NXP/TARGET_LPC82X/i2c_api.c Thu Apr 09 06:45:08 2015 +0100 +++ b/targets/hal/TARGET_NXP/TARGET_LPC82X/i2c_api.c Thu Apr 09 07:00:08 2015 +0100 @@ -20,30 +20,19 @@ #include "cmsis.h" #include "pinmap.h" -#include "rom_i2c_8xx.h" +#define LPC824_I2C0_FMPLUS 1 #if DEVICE_I2C -typedef struct ROM_API { - const uint32_t unused[5]; - const I2CD_API_T *pI2CD; /*!< I2C driver routines functions table */ -} LPC_ROM_API_T; - - -/* Pointer to ROM API function address */ -#define LPC_ROM_API_BASE_LOC 0x1FFF1FF8UL -#define LPC_ROM_API (*(LPC_ROM_API_T * *) LPC_ROM_API_BASE_LOC) - -/* Pointer to @ref I2CD_API_T functions in ROM */ -#define LPC_I2CD_API ((LPC_ROM_API)->pI2CD) - static const SWM_Map SWM_I2C_SDA[] = { - { 9, 8}, + //PINASSIGN Register ID, Pinselect bitfield position + { 9, 8}, { 9, 24}, {10, 8}, }; static const SWM_Map SWM_I2C_SCL[] = { + //PINASSIGN Register ID, Pinselect bitfield position { 9, 16}, {10, 0}, {10, 16}, @@ -52,36 +41,15 @@ static int i2c_used = 0; static uint8_t repeated_start = 0; -static uint32_t *i2c_buffer; #define I2C_DAT(x) (x->i2c->MSTDAT) #define I2C_STAT(x) ((x->i2c->STAT >> 1) & (0x07)) -static inline int i2c_status(i2c_t *obj) -{ - return I2C_STAT(obj); -} - -// Wait until the Serial Interrupt (SI) is set -static int i2c_wait_SI(i2c_t *obj) -{ - volatile int timeout = 0; - while (!(obj->i2c->STAT & (1 << 0))) { - timeout++; - if (timeout > 100000) return -1; - } - return 0; -} - -static inline void i2c_interface_enable(i2c_t *obj) -{ - obj->i2c->CFG |= 1; -} - static inline void i2c_power_enable(int ch) { switch(ch) { case 0: + // I2C0, Same as for LPC812 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 5); LPC_SYSCON->PRESETCTRL &= ~(1 << 6); LPC_SYSCON->PRESETCTRL |= (1 << 6); @@ -89,6 +57,7 @@ case 1: case 2: case 3: + // I2C1,I2C2 or I2C3. Not available for LPC812 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << (20 + ch)); LPC_SYSCON->PRESETCTRL &= ~(1 << (13 + ch)); LPC_SYSCON->PRESETCTRL |= (1 << (13 + ch)); @@ -99,6 +68,12 @@ } +static inline void i2c_interface_enable(i2c_t *obj) { + obj->i2c->CFG |= (1 << 0); // Enable Master mode +// obj->i2c->CFG &= ~(1 << 1); // Disable Slave mode +} + + static int get_available_i2c(void) { int i; for (i=0; i<3; i++) { @@ -113,11 +88,23 @@ const SWM_Map *swm; uint32_t regVal; int i2c_ch = 0; - + + //LPC824 + //I2C0 can support FM+ but only on P0_11 and P0_10 if (sda == I2C_SDA && scl == I2C_SCL) { - LPC_SWM->PINENABLE0 &= ~(0x3 << 11); + //Select I2C mode for P0_11 and P0_10 + LPC_SWM->PINENABLE0 &= ~(0x3 << 11); + +#if(LPC824_I2C0_FMPLUS == 1) + // Enable FM+ mode on P0_11, P0_10 + LPC_IOCON->PIO0_10 &= ~(0x3 << 8); + LPC_IOCON->PIO0_10 |= (0x2 << 8); //FM+ mode + LPC_IOCON->PIO0_11 &= ~(0x3 << 8); + LPC_IOCON->PIO0_11 |= (0x2 << 8); //FM+ mode +#endif } else { + //Select any other pin for I2C1, I2C2 or I2C3 i2c_ch = get_available_i2c(); if (i2c_ch == -1) return; @@ -151,127 +138,213 @@ // enable power i2c_power_enable(i2c_ch); - - uint32_t size_in_bytes = LPC_I2CD_API->i2c_get_mem_size(); - i2c_buffer = malloc(size_in_bytes); - obj->handler = LPC_I2CD_API->i2c_setup((uint32_t)(obj->i2c), i2c_buffer); - LPC_I2CD_API->i2c_set_bitrate(obj->handler, SystemCoreClock, 100000); - LPC_I2CD_API->i2c_set_timeout(obj->handler, 100000); - + // set default frequency at 100k + i2c_frequency(obj, 100000); i2c_interface_enable(obj); } -inline int i2c_start(i2c_t *obj) -{ + +static inline int i2c_status(i2c_t *obj) { + return I2C_STAT(obj); +} + +// Wait until the Master Serial Interrupt (SI) is set +// Timeout when it takes too long. +static int i2c_wait_SI(i2c_t *obj) { + int timeout = 0; + while (!(obj->i2c->STAT & (1 << 0))) { + timeout++; + if (timeout > 100000) return -1; + } + return 0; +} + + +//Attention. Spec says: First store Address in DAT before setting STA ! +//Undefined state when using single byte I2C operations and too much delay +//between i2c_start and do_i2c_write(Address). +//Also note that lpc812/824 will immediately continue reading a byte when Address b0 == 1 +inline int i2c_start(i2c_t *obj) { int status = 0; if (repeated_start) { - obj->i2c->MSTCTL = (1 << 1) | (1 << 0); + obj->i2c->MSTCTL = (1 << 1) | (1 << 0); // STA bit and Continue bit to complete previous RD or WR repeated_start = 0; } else { - obj->i2c->MSTCTL = (1 << 1); + obj->i2c->MSTCTL = (1 << 1); // STA bit } return status; } -inline int i2c_stop(i2c_t *obj) -{ - volatile int timeout = 0; +//Generate Stop condition and wait until bus is Idle +//Will also send NAK for previous RD +inline int i2c_stop(i2c_t *obj) { + int timeout = 0; + // STP bit and Continue bit. Sends NAK to complete previous RD obj->i2c->MSTCTL = (1 << 2) | (1 << 0); - while ((obj->i2c->STAT & ((1 << 0) | (7 << 1))) != ((1 << 0) | (0 << 1))) { + + //Spin until Ready (b0 == 1)and Status is Idle (b3..b1 == 000) + while ((obj->i2c->STAT & ((7 << 1) | (1 << 0))) != ((0 << 1) | (1 << 0))) { timeout ++; if (timeout > 100000) return 1; } + // repeated_start = 0; // bus free return 0; } -static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) -{ +//Spec says: first check Idle and status is Ok +static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) { // write the data I2C_DAT(obj) = value; - + if (!addr) - obj->i2c->MSTCTL = (1 << 0); - + obj->i2c->MSTCTL = (1 << 0); //Set continue for data. Should not be set for addr since that uses STA + // wait and return status i2c_wait_SI(obj); return i2c_status(obj); } -static inline int i2c_do_read(i2c_t *obj, int last) -{ + +//Attention, correct Order: wait for data ready, read data, read status, continue, return +//Dont read DAT or STAT when not ready, so dont read after setting continue. +//Results may be invalid when next read is underway. +static inline int i2c_do_read(i2c_t *obj, int last) { // wait for it to arrive i2c_wait_SI(obj); if (!last) - obj->i2c->MSTCTL = (1 << 0); - + obj->i2c->MSTCTL = (1 << 0); //ACK and Continue + // return the data return (I2C_DAT(obj) & 0xFF); } -void i2c_frequency(i2c_t *obj, int hz) -{ - LPC_I2CD_API->i2c_set_bitrate(obj->handler, SystemCoreClock, hz); + +void i2c_frequency(i2c_t *obj, int hz) { + // No peripheral clock divider on the M0 + uint32_t PCLK = SystemCoreClock; + + uint32_t clkdiv = PCLK / (hz * 4) - 1; + + obj->i2c->CLKDIV = clkdiv; + obj->i2c->MSTTIME = 0; } -int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) -{ - ErrorCode_t err; - I2C_PARAM_T i2c_param; - I2C_RESULT_T i2c_result; +// The I2C does a read or a write as a whole operation +// There are two types of error conditions it can encounter +// 1) it can not obtain the bus +// 2) it gets error responses at part of the transmission +// +// We tackle them as follows: +// 1) we retry until we get the bus. we could have a "timeout" if we can not get it +// which basically turns it in to a 2) +// 2) on error, we use the standard error mechanisms to report/debug +// +// Therefore an I2C transaction should always complete. If it doesn't it is usually +// because something is setup wrong (e.g. wiring), and we don't need to programatically +// check for that +int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { + int count, status; + + //Store the address+RD and then generate STA + I2C_DAT(obj) = address | 0x01; + i2c_start(obj); + + // Wait for completion of STA and Sending of SlaveAddress+RD and first Read byte + i2c_wait_SI(obj); + status = i2c_status(obj); + if (status == 0x03) { // NAK on SlaveAddress + i2c_stop(obj); + return I2C_ERROR_NO_SLAVE; + } - uint8_t *buf = malloc(length + 1); - buf[0] = (uint8_t)((address | 0x01) & 0xFF); - i2c_param.buffer_ptr_rec = buf; - i2c_param.num_bytes_rec = length + 1; - i2c_param.stop_flag = stop; - err = LPC_I2CD_API->i2c_master_receive_poll(obj->handler, &i2c_param, &i2c_result); - memcpy(data, buf + 1, i2c_result.n_bytes_recd); - free(buf); - if (err == 0) - return i2c_result.n_bytes_recd - 1; - else - return -1; + // Read in all except last byte + for (count = 0; count < (length-1); count++) { + + // Wait for it to arrive, note that first byte read after address+RD is already waiting + i2c_wait_SI(obj); + status = i2c_status(obj); + if (status != 0x01) { // RX RDY + i2c_stop(obj); + return count; + } + data[count] = I2C_DAT(obj) & 0xFF; // Store read byte + + obj->i2c->MSTCTL = (1 << 0); // Send ACK and Continue to read + } + + // Read final byte + // Wait for it to arrive + i2c_wait_SI(obj); + + status = i2c_status(obj); + if (status != 0x01) { // RX RDY + i2c_stop(obj); + return count; + } + data[count] = I2C_DAT(obj) & 0xFF; // Store final read byte + + // If not repeated start, send stop. + if (stop) { + i2c_stop(obj); // Also sends NAK for last read byte + } else { + repeated_start = 1; + } + + return length; } -int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) -{ - ErrorCode_t err; - I2C_PARAM_T i2c_param; - I2C_RESULT_T i2c_result; + +int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { + int i, status; - uint8_t *buf = malloc(length + 1); - buf[0] = (uint8_t)(address & 0xFE); - memcpy(buf + 1, data, length); - i2c_param.buffer_ptr_send = buf; - i2c_param.num_bytes_send = length + 1; - i2c_param.stop_flag = stop; - err = LPC_I2CD_API->i2c_master_transmit_poll(obj->handler, &i2c_param, &i2c_result); - free(buf); - if (err == 0) - return i2c_result.n_bytes_sent - 1; - else - return -1; + //Store the address+/WR and then generate STA + I2C_DAT(obj) = address & 0xFE; + i2c_start(obj); + + // Wait for completion of STA and Sending of SlaveAddress+/WR + i2c_wait_SI(obj); + status = i2c_status(obj); + if (status == 0x03) { // NAK SlaveAddress + i2c_stop(obj); + return I2C_ERROR_NO_SLAVE; + } + + //Write all bytes + for (i=0; i<length; i++) { + status = i2c_do_write(obj, data[i], 0); + if (status != 0x02) { // TX RDY. Handles a Slave NAK on datawrite + i2c_stop(obj); + return i; + } + } + + // If not repeated start, send stop. + if (stop) { + i2c_stop(obj); + } else { + repeated_start = 1; + } + + return length; } -void i2c_reset(i2c_t *obj) -{ +void i2c_reset(i2c_t *obj) { i2c_stop(obj); } -int i2c_byte_read(i2c_t *obj, int last) -{ +int i2c_byte_read(i2c_t *obj, int last) { return (i2c_do_read(obj, last) & 0xFF); +// return (i2c_do_read(obj, last, 0) & 0xFF); } -int i2c_byte_write(i2c_t *obj, int data) -{ +int i2c_byte_write(i2c_t *obj, int data) { int ack; int status = i2c_do_write(obj, (data & 0xFF), 0); - + switch(status) { - case 2: + case 2: // TX RDY. Handles a Slave NAK on datawrite ack = 1; break; default: @@ -282,77 +355,242 @@ return ack; } + #if DEVICE_I2CSLAVE -void i2c_slave_mode(i2c_t *obj, int enable_slave) -{ - obj->handler = LPC_I2CD_API->i2c_setup((uint32_t)(obj->i2c), i2c_buffer); - if (enable_slave != 0) { - obj->i2c->CFG &= ~(1 << 0); - obj->i2c->CFG |= (1 << 1); +#define I2C_SLVDAT(x) (x->i2c->SLVDAT) +#define I2C_SLVSTAT(x) ((x->i2c->STAT >> 9) & (0x03)) +#define I2C_SLVSI(x) ((x->i2c->STAT >> 8) & (0x01)) +//#define I2C_SLVCNT(x) (x->i2c->SLVCTL = (1 << 0)) +//#define I2C_SLVNAK(x) (x->i2c->SLVCTL = (1 << 1)) + +#if(0) +// Wait until the Slave Serial Interrupt (SI) is set +// Timeout when it takes too long. +static int i2c_wait_slave_SI(i2c_t *obj) { + int timeout = 0; + while (!(obj->i2c->STAT & (1 << 8))) { + timeout++; + if (timeout > 100000) return -1; } - else { - obj->i2c->CFG |= (1 << 0); - obj->i2c->CFG &= ~(1 << 1); - } + return 0; +} +#endif + +void i2c_slave_mode(i2c_t *obj, int enable_slave) { + + if (enable_slave) { +// obj->i2c->CFG &= ~(1 << 0); //Disable Master mode + obj->i2c->CFG |= (1 << 1); //Enable Slave mode + } + else { +// obj->i2c->CFG |= (1 << 0); //Enable Master mode + obj->i2c->CFG &= ~(1 << 1); //Disable Slave mode + } +} +// Wait for next I2C event and find out what is going on +// +int i2c_slave_receive(i2c_t *obj) { + int addr; + + // Check if there is any data pending + if (! I2C_SLVSI(obj)) { + return 0; //NoData + }; + + // Check State + switch(I2C_SLVSTAT(obj)) { + case 0x0: // Slave address plus R/W received + // At least one of the four slave addresses has been matched by hardware. + // You can figure out which address by checking Slave address match Index in STAT register. + + // Get the received address + addr = I2C_SLVDAT(obj) & 0xFF; + // Send ACK on address and Continue + obj->i2c->SLVCTL = (1 << 0); + + if (addr == 0x00) { + return 2; //WriteGeneral + } + //check the RW bit + if ((addr & 0x01) == 0x01) { + return 1; //ReadAddressed + } + else { + return 3; //WriteAddressed + } + //break; + + case 0x1: // Slave receive. Received data is available (Slave Receiver mode). + // Oops, should never get here... + obj->i2c->SLVCTL = (1 << 1); // Send NACK on received data, try to recover... + return 0; //NoData + + case 0x2: // Slave transmit. Data can be transmitted (Slave Transmitter mode). + // Oops, should never get here... + I2C_SLVDAT(obj) = 0xFF; // Send dummy data for transmission + obj->i2c->SLVCTL = (1 << 0); // Continue and try to recover... + return 0; //NoData + + case 0x3: // Reserved. + default: // Oops, should never get here... + obj->i2c->SLVCTL = (1 << 0); // Continue and try to recover... + return 0; //NoData + //break; + } //switch status +} + +// The dedicated I2C Slave byte read and byte write functions need to be called +// from 'common' mbed I2CSlave API for devices that have separate Master and +// Slave engines such as the lpc812 and lpc1549. + +//Called when Slave is addressed for Write, Slave will receive Data in polling mode +//Parameter last=1 means received byte will be NACKed. +int i2c_slave_byte_read(i2c_t *obj, int last) { + int data; + + // Wait for data + while (!I2C_SLVSI(obj)); // Wait forever +//if (i2c_wait_slave_SI(obj) != 0) {return -2;} // Wait with timeout + + // Dont bother to check State, were not returning it anyhow.. +//if (I2C_SLVSTAT(obj)) == 0x01) { + // Slave receive. Received data is available (Slave Receiver mode). +//}; + + data = I2C_SLVDAT(obj) & 0xFF; // Get and store the received data + if (last) { + obj->i2c->SLVCTL = (1 << 1); // Send NACK on received data and Continue + } + else { + obj->i2c->SLVCTL = (1 << 0); // Send ACK on data and Continue to read + } + + return data; } -int i2c_slave_receive(i2c_t *obj) -{ - CHIP_I2C_MODE_T mode; - int ret; - - mode = LPC_I2CD_API->i2c_get_status(obj->handler); - switch(mode) { - case SLAVE_SEND: - ret = 1; - break; - case SLAVE_RECEIVE: - ret = 3; - break; - case MASTER_SEND: - case MASTER_RECEIVE: - default: - ret = 0; - break; - } - return ret; + +//Called when Slave is addressed for Read, Slave will send Data in polling mode +// +int i2c_slave_byte_write(i2c_t *obj, int data) { + + // Wait until Ready + while (!I2C_SLVSI(obj)); // Wait forever +// if (i2c_wait_slave_SI(obj) != 0) {return -2;} // Wait with timeout + + // Check State + switch(I2C_SLVSTAT(obj)) { + case 0x0: // Slave address plus R/W received + // At least one of the four slave addresses has been matched by hardware. + // You can figure out which address by checking Slave address match Index in STAT register. + // I2C Restart occurred + return -1; + //break; + case 0x1: // Slave receive. Received data is available (Slave Receiver mode). + // Should not get here... + return -2; + //break; + case 0x2: // Slave transmit. Data can be transmitted (Slave Transmitter mode). + I2C_SLVDAT(obj) = data & 0xFF; // Store the data for transmission + obj->i2c->SLVCTL = (1 << 0); // Continue to send + + return 1; + //break; + case 0x3: // Reserved. + default: + // Should not get here... + return -3; + //break; + } // switch status } -int i2c_slave_read(i2c_t *obj, char *data, int length) -{ - ErrorCode_t err; - I2C_PARAM_T i2c_param; - I2C_RESULT_T i2c_result; + +//Called when Slave is addressed for Write, Slave will receive Data in polling mode +//Parameter length (>=1) is the maximum allowable number of bytes. All bytes will be ACKed. +int i2c_slave_read(i2c_t *obj, char *data, int length) { + int count=0; + + // Read and ACK all expected bytes + while (count < length) { + // Wait for data + while (!I2C_SLVSI(obj)); // Wait forever +// if (i2c_wait_slave_SI(obj) != 0) {return -2;} // Wait with timeout - i2c_param.buffer_ptr_send = (uint8_t *)data; - i2c_param.num_bytes_send = length; - err = LPC_I2CD_API->i2c_slave_transmit_poll(obj->handler, &i2c_param, &i2c_result); - if (err == 0) - return i2c_result.n_bytes_sent; - else - return -1; + // Check State + switch(I2C_SLVSTAT(obj)) { + case 0x0: // Slave address plus R/W received + // At least one of the four slave addresses has been matched by hardware. + // You can figure out which address by checking Slave address match Index in STAT register. + // I2C Restart occurred + return -1; + //break; + + case 0x1: // Slave receive. Received data is available (Slave Receiver mode). + data[count] = I2C_SLVDAT(obj) & 0xFF; // Get and store the received data + obj->i2c->SLVCTL = (1 << 0); // Send ACK on data and Continue to read + break; + + case 0x2: // Slave transmit. Data can be transmitted (Slave Transmitter mode). + case 0x3: // Reserved. + default: // Should never get here... + return -2; + //break; + } // switch status + + count++; + } // for all bytes + + return count; // Received the expected number of bytes } -int i2c_slave_write(i2c_t *obj, const char *data, int length) -{ - ErrorCode_t err; - I2C_PARAM_T i2c_param; - I2C_RESULT_T i2c_result; + +//Called when Slave is addressed for Read, Slave will send Data in polling mode +//Parameter length (>=1) is the maximum number of bytes. Exit when Slave byte is NACKed. +int i2c_slave_write(i2c_t *obj, const char *data, int length) { + int count; + + // Send and all bytes or Exit on NAK + for (count=0; count < length; count++) { + // Wait until Ready for data + while (!I2C_SLVSI(obj)); // Wait forever +// if (i2c_wait_slave_SI(obj) != 0) {return -2;} // Wait with timeout - i2c_param.buffer_ptr_rec = (uint8_t *)data; - i2c_param.num_bytes_rec = length; - err = LPC_I2CD_API->i2c_slave_receive_poll(obj->handler, &i2c_param, &i2c_result); - if (err == 0) - return i2c_result.n_bytes_recd; - else - return -1; + // Check State + switch(I2C_SLVSTAT(obj)) { + case 0x0: // Slave address plus R/W received + // At least one of the four slave addresses has been matched by hardware. + // You can figure out which address by checking Slave address match Index in STAT register. + // I2C Restart occurred + return -1; + //break; + case 0x1: // Slave receive. Received data is available (Slave Receiver mode). + // Should not get here... + return -2; + //break; + case 0x2: // Slave transmit. Data can be transmitted (Slave Transmitter mode). + I2C_SLVDAT(obj) = data[count] & 0xFF; // Store the data for transmission + obj->i2c->SLVCTL = (1 << 0); // Continue to send + break; + case 0x3: // Reserved. + default: + // Should not get here... + return -3; + //break; + } // switch status + } // for all bytes + + return length; // Transmitted the max number of bytes } -void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) -{ - LPC_I2CD_API->i2c_set_slave_addr(obj->handler, address, 0); + +// Set the four slave addresses. +void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) { + obj->i2c->SLVADR0 = (address & 0xFE); // Store address in address 0 register + obj->i2c->SLVADR1 = (0x00 & 0xFE); // Store general call write address in address 1 register + obj->i2c->SLVADR2 = (0x01); // Disable address 2 register + obj->i2c->SLVADR3 = (0x01); // Disable address 3 register + obj->i2c->SLVQUAL0 = (mask & 0xFE); // Qualifier mask for address 0 register. Any maskbit that is 1 will always be a match } #endif
--- a/targets/hal/TARGET_NXP/TARGET_LPC82X/us_ticker.c Thu Apr 09 06:45:08 2015 +0100 +++ b/targets/hal/TARGET_NXP/TARGET_LPC82X/us_ticker.c Thu Apr 09 07:00:08 2015 +0100 @@ -18,72 +18,89 @@ #include "PeripheralNames.h" static int us_ticker_inited = 0; -static int ticker_expired = 0; +int MRT_Clock_MHz; +unsigned int ticker_fullcount_us; +unsigned long int ticker_expired_count_us = 0; #define US_TICKER_TIMER_IRQn MRT_IRQn -#define MRT_CLOCK_MHZ 30 -void us_ticker_init(void) -{ +void us_ticker_init(void) { + if (us_ticker_inited) return; us_ticker_inited = 1; + // Calculate MRT clock value (MRT has no prescaler) + MRT_Clock_MHz = (SystemCoreClock / 1000000); + // Calculate fullcounter value in us (MRT has 31 bits and clock is 30MHz) + ticker_fullcount_us = 0x80000000UL/MRT_Clock_MHz; + // Enable the MRT clock LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 10); // Clear peripheral reset the MRT LPC_SYSCON->PRESETCTRL |= (1 << 7); - // Force load interval value + // Force load interval value (Bit 0-30 is interval value, Bit 31 is Force Load bit) LPC_MRT->INTVAL0 = 0xFFFFFFFFUL; - // Enable ch0 interrupt - LPC_MRT->CTRL0 = 1; + // Enable Ch0 interrupt, Mode 0 is Repeat Interrupt + LPC_MRT->CTRL0 = (0x0 << 1) | (0x1 << 0); - // Force load interval value + // Force load interval value (Bit 0-30 is interval value, Bit 31 is Force Load bit) LPC_MRT->INTVAL1 = 0x80000000UL; - // Disable ch1 interrupt - LPC_MRT->CTRL1 = 0; - + // Disable ch1 interrupt, Mode 0 is Repeat Interrupt + LPC_MRT->CTRL1 = (0x0 << 1) | (0x0 << 0); + // Set MRT interrupt vector NVIC_SetVector(US_TICKER_TIMER_IRQn, (uint32_t)us_ticker_irq_handler); NVIC_EnableIRQ(US_TICKER_TIMER_IRQn); } -uint32_t us_ticker_read() -{ +//TIMER0 is used for us ticker and timers (Timer, wait(), wait_us() etc) +uint32_t us_ticker_read() { + if (!us_ticker_inited) us_ticker_init(); // Generate ticker value - // MRT source clock is SystemCoreClock (30MHz) and 31-bit down count timer - // Calculate expected value using number of expired times - return (0x7FFFFFFFUL - LPC_MRT->TIMER0)/MRT_CLOCK_MHZ + (ticker_expired * (0x80000000UL/MRT_CLOCK_MHZ)); + // MRT source clock is SystemCoreClock (30MHz) and MRT is a 31-bit countdown timer + // Calculate expected value using number of expired times to mimic a 32bit timer @ 1 MHz + return (0x7FFFFFFFUL - LPC_MRT->TIMER0)/MRT_Clock_MHz + ticker_expired_count_us; } - -void us_ticker_set_interrupt(timestamp_t timestamp) -{ - // Force load interval value - LPC_MRT->INTVAL1 = (((timestamp - us_ticker_read()) * MRT_CLOCK_MHZ) | 0x80000000UL); - +//TIMER1 is used for Timestamped interrupts (Ticker(), Timeout()) +void us_ticker_set_interrupt(timestamp_t timestamp) { + + // MRT source clock is SystemCoreClock (30MHz) and MRT is a 31-bit countdown timer + // Force load interval value (Bit 0-30 is interval value, Bit 31 is Force Load bit) + // Note: The MRT has less counter headroom available than the typical mbed 32bit timer @ 1 MHz. + // The calculated counter interval until the next timestamp will be truncated and an + // 'early' interrupt will be generated in case the max required count interval exceeds + // the available 31 bits space. However, the mbed us_ticker interrupt handler will + // check current time against the next scheduled timestamp and simply re-issue the + // same interrupt again when needed. The calculated counter interval will now be smaller. + LPC_MRT->INTVAL1 = (((timestamp - us_ticker_read()) * MRT_Clock_MHz) | 0x80000000UL); + // Enable interrupt LPC_MRT->CTRL1 |= 1; } -void us_ticker_disable_interrupt() -{ +//Disable Timestamped interrupts triggered by TIMER1 +void us_ticker_disable_interrupt() { + //Timer1 for Timestamped interrupts (31 bits downcounter @ SystemCoreClock) LPC_MRT->CTRL1 &= ~1; } -void us_ticker_clear_interrupt() -{ +void us_ticker_clear_interrupt() { + + //Timer1 for Timestamped interrupts (31 bits downcounter @ SystemCoreClock) if (LPC_MRT->STAT1 & 1) LPC_MRT->STAT1 = 1; + //Timer0 for us counter (31 bits downcounter @ SystemCoreClock) if (LPC_MRT->STAT0 & 1) { LPC_MRT->STAT0 = 1; - ticker_expired++; + ticker_expired_count_us += ticker_fullcount_us; } }