Mouse code for the MacroRat
mbed-dev/targets/TARGET_RENESAS/TARGET_VK_RZ_A1H/i2c_api.c
- Committer:
- sahilmgandhi
- Date:
- 2017-05-14
- Revision:
- 18:6a4db94011d3
File content as of revision 18:6a4db94011d3:
/* mbed Microcontroller Library * Copyright (c) 2006-2013 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mbed_assert.h" #include "i2c_api.h" #include "cmsis.h" #include "pinmap.h" #include "r_typedefs.h" #include "riic_iodefine.h" #include "RZ_A1_Init.h" #include "VKRZA1H.h" volatile struct st_riic *RIIC[] = RIIC_ADDRESS_LIST; #define REG(N) \ RIIC[obj->i2c]->RIICn##N /* RIICnCR1 */ #define CR1_RST (1 << 6) #define CR1_ICE (1 << 7) /* RIICnCR2 */ #define CR2_ST (1 << 1) #define CR2_RS (1 << 2) #define CR2_SP (1 << 3) #define CR2_TRS (1 << 5) #define CR2_BBSY (1 << 7) /* RIICnMR3 */ #define MR3_ACKBT (1 << 3) #define MR3_ACKWP (1 << 4) #define MR3_WAIT (1 << 6) /* RIICnSER */ #define SER_SAR0E (1 << 0) /* RIICnSR1 */ #define SR1_AAS0 (1 << 0) /* RIICnSR2 */ #define SR2_START (1 << 2) #define SR2_STOP (1 << 3) #define SR2_NACKF (1 << 4) #define SR2_RDRF (1 << 5) #define SR2_TEND (1 << 6) #define SR2_TDRE (1 << 7) #define WAIT_TIMEOUT (3600000) /* Loop counter : Time-out is about 1s. By 3600000 loops, measured value is 969ms. */ static const PinMap PinMap_I2C_SDA[] = { {P1_1 , I2C_0, 1}, {P1_3 , I2C_1, 1}, {P1_5 , I2C_2, 1}, {P1_7 , I2C_3, 1}, {NC , NC , 0} }; static const PinMap PinMap_I2C_SCL[] = { {P1_0 , I2C_0, 1}, {P1_2 , I2C_1, 1}, {P1_4 , I2C_2, 1}, {P1_6 , I2C_3, 1}, {NC , NC, 0} }; static inline int i2c_status(i2c_t *obj) { return REG(SR2.UINT8[0]); } static void i2c_reg_reset(i2c_t *obj) { /* full reset */ REG(CR1.UINT8[0]) &= ~CR1_ICE; // CR1.ICE off REG(CR1.UINT8[0]) |= CR1_RST; // CR1.IICRST on REG(CR1.UINT8[0]) |= CR1_ICE; // CR1.ICE on REG(MR1.UINT8[0]) = 0x08; // P_phi /x 9bit (including Ack) REG(SER.UINT8[0]) = 0x00; // no slave addr enabled /* set frequency */ REG(MR1.UINT8[0]) |= obj->pclk_bit; REG(BRL.UINT8[0]) = obj->width_low; REG(BRH.UINT8[0]) = obj->width_hi; REG(MR2.UINT8[0]) = 0x07; REG(MR3.UINT8[0]) = 0x00; REG(FER.UINT8[0]) = 0x72; // SCLE, NFE enabled, TMOT REG(IER.UINT8[0]) = 0x00; // no interrupt REG(CR1.UINT32) &= ~CR1_RST; // CR1.IICRST negate reset } static inline int i2c_wait_RDRF(i2c_t *obj) { int timeout = 0; /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_RDRF) == 0) { timeout ++; if (timeout >= WAIT_TIMEOUT) { return -1; } } return 0; } static int i2c_wait_TDRE(i2c_t *obj) { int timeout = 0; /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_TDRE) == 0) { timeout ++; if (timeout >= WAIT_TIMEOUT) { return -1; } } return 0; } static int i2c_wait_TEND(i2c_t *obj) { int timeout = 0; /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_TEND) == 0) { timeout ++; if (timeout >= WAIT_TIMEOUT) { return -1; } } return 0; } static int i2c_wait_START(i2c_t *obj) { int timeout = 0; /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_START) == 0) { timeout ++; if (timeout >= WAIT_TIMEOUT) { return -1; } } return 0; } static int i2c_wait_STOP(i2c_t *obj) { int timeout = 0; /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_STOP) == 0) { timeout ++; if (timeout >= WAIT_TIMEOUT) { return -1; } } return 0; } static int i2c_set_STOP(i2c_t *obj) { /* SR2.STOP = 0 */ REG(SR2.UINT32) &= ~SR2_STOP; /* Stop condition */ REG(CR2.UINT32) |= CR2_SP; return 0; } static void i2c_set_SR2_NACKF_STOP(i2c_t *obj) { /* SR2.NACKF = 0 */ REG(SR2.UINT32) &= ~SR2_NACKF; /* SR2.STOP = 0 */ REG(SR2.UINT32) &= ~SR2_STOP; } static void i2c_set_MR3_NACK(i2c_t *obj) { /* send a NOT ACK */ REG(MR3.UINT32) |= MR3_ACKWP; REG(MR3.UINT32) |= MR3_ACKBT; REG(MR3.UINT32) &= ~MR3_ACKWP; } static void i2c_set_MR3_ACK(i2c_t *obj) { /* send a ACK */ REG(MR3.UINT32) |= MR3_ACKWP; REG(MR3.UINT32) &= ~MR3_ACKBT; REG(MR3.UINT32) &= ~MR3_ACKWP; } static inline void i2c_power_enable(i2c_t *obj) { volatile uint8_t dummy; switch ((int)obj->i2c) { case I2C_0: CPGSTBCR9 &= ~(0x80); break; case I2C_1: CPGSTBCR9 &= ~(0x40); break; case I2C_2: CPGSTBCR9 &= ~(0x20); break; case I2C_3: CPGSTBCR9 &= ~(0x10); break; } dummy = CPGSTBCR9; } void i2c_init(i2c_t *obj, PinName sda, PinName scl) { /* determine the I2C to use */ I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA); I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL); obj->i2c = pinmap_merge(i2c_sda, i2c_scl); MBED_ASSERT((int)obj->i2c != NC); /* enable power */ i2c_power_enable(obj); /* set default frequency at 100k */ i2c_frequency(obj, 100000); pinmap_pinout(sda, PinMap_I2C_SDA); pinmap_pinout(scl, PinMap_I2C_SCL); obj->last_stop_flag = 1; } inline int i2c_start(i2c_t *obj) { int timeout = 0; while ((REG(CR2.UINT32) & CR2_BBSY) != 0) { timeout ++; if (timeout >= obj->bbsy_wait_cnt) { break; } } /* Start Condition */ REG(CR2.UINT8[0]) |= CR2_ST; return 0; } static inline int i2c_restart(i2c_t *obj) { /* SR2.START = 0 */ REG(SR2.UINT32) &= ~SR2_START; /* ReStart condition */ REG(CR2.UINT32) |= CR2_RS; return 0; } inline int i2c_stop(i2c_t *obj) { (void)i2c_set_STOP(obj); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); return 0; } static void i2c_set_err_noslave(i2c_t *obj) { (void)i2c_set_STOP(obj); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); obj->last_stop_flag = 1; } static inline int i2c_do_write(i2c_t *obj, int value) { int timeout = 0; /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_TDRE) == 0) { timeout ++; if (timeout >= WAIT_TIMEOUT) { return -1; } } /* write the data */ REG(DRT.UINT32) = value; return 0; } static inline int i2c_read_address_write(i2c_t *obj, int value) { int status; status = i2c_wait_TDRE(obj); if (status == 0) { /* write the data */ REG(DRT.UINT32) = value; } return status; } static inline int i2c_do_read(i2c_t *obj, int last) { if (last == 2) { /* this time is befor last byte read */ /* Set MR3 WAIT bit is 1 */; REG(MR3.UINT32) |= MR3_WAIT; } else if (last == 1) { i2c_set_MR3_NACK(obj); } else { i2c_set_MR3_ACK(obj); } /* return the data */ return (REG(DRR.UINT32) & 0xFF); } void i2c_frequency(i2c_t *obj, int hz) { float64_t pclk_val; float64_t wait_utime; volatile float64_t bps; volatile float64_t L_time; /* H Width period */ volatile float64_t H_time; /* L Width period */ uint32_t tmp_L_width; uint32_t tmp_H_width; uint32_t remainder; uint32_t wk_cks = 0; /* set PCLK */ if (false == RZ_A1_IsClockMode0()) { pclk_val = (float64_t)CM1_RENESAS_RZ_A1_P0_CLK; } else { pclk_val = (float64_t)CM0_RENESAS_RZ_A1_P0_CLK; } /* Min 10kHz, Max 400kHz */ if (hz < 10000) { bps = 10000; } else if (hz > 400000) { bps = 400000; } else { bps = (float64_t)hz; } /* Calculation L width time */ L_time = (1 / (2 * bps)); /* Harf period of frequency */ H_time = L_time; /* Check I2C mode of Speed */ if (bps > 100000) { /* Fast-mode */ L_time -= 102E-9; /* Falling time of SCL clock. */ H_time -= 138E-9; /* Rising time of SCL clock. */ /* Check L wideth */ if (L_time < 1.3E-6) { /* Wnen L width less than 1.3us */ /* Subtract Rise up and down time for SCL from H/L width */ L_time = 1.3E-6; H_time = (1 / bps) - L_time - 138E-9 - 102E-9; } } tmp_L_width = (uint32_t)(L_time * pclk_val * 10); tmp_L_width >>= 1; wk_cks++; while (tmp_L_width >= 341) { tmp_L_width >>= 1; wk_cks++; } remainder = tmp_L_width % 10; tmp_L_width = ((tmp_L_width + 9) / 10) - 3; /* carry */ tmp_H_width = (uint32_t)(H_time * pclk_val * 10); tmp_H_width >>= wk_cks; if (remainder == 0) { tmp_H_width = ((tmp_H_width + 9) / 10) - 3; /* carry */ } else { remainder += tmp_H_width % 10; tmp_H_width = (tmp_H_width / 10) - 3; if (remainder > 10) { tmp_H_width += 1; /* fine adjustment */ } } /* timeout of BBSY bit is minimum low width by frequency */ /* so timeout calculates "(low width) * 2" by frequency */ wait_utime = (L_time * 2) * 1000000; /* 1 wait of BBSY bit is about 0.3us. if it's below 0.3us, wait count is set as 1. */ if (wait_utime <= 0.3) { obj->bbsy_wait_cnt = 1; } else { obj->bbsy_wait_cnt = (int)(wait_utime / 0.3); } /* I2C Rate */ obj->pclk_bit = (uint8_t)(0x10 * wk_cks); /* P_phi / xx */ obj->width_low = (uint8_t)(tmp_L_width | 0x000000E0); obj->width_hi = (uint8_t)(tmp_H_width | 0x000000E0); /* full reset */ i2c_reg_reset(obj); } int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { int count = 0; int status; int value; volatile uint32_t work_reg = 0; i2c_set_MR3_ACK(obj); /* There is a STOP condition for last processing */ if (obj->last_stop_flag != 0) { status = i2c_start(obj); if (status != 0) { i2c_set_err_noslave(obj); return I2C_ERROR_BUS_BUSY; } } obj->last_stop_flag = stop; /* Send Slave address */ status = i2c_read_address_write(obj, (address | 0x01)); if (status != 0) { i2c_set_err_noslave(obj); return I2C_ERROR_NO_SLAVE; } /* wait RDRF */ status = i2c_wait_RDRF(obj); /* check ACK/NACK */ if ((status != 0) || ((REG(SR2.UINT32) & SR2_NACKF) != 0)) { /* Slave sends NACK */ (void)i2c_set_STOP(obj); /* dummy read */ value = REG(DRR.UINT32); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); obj->last_stop_flag = 1; return I2C_ERROR_NO_SLAVE; } if (length != 0) { /* Read in all except last byte */ if (length > 2) { /* dummy read */ value = REG(DRR.UINT32); for (count = 0; count < (length - 1); count++) { /* wait for it to arrive */ status = i2c_wait_RDRF(obj); if (status != 0) { i2c_set_err_noslave(obj); return I2C_ERROR_NO_SLAVE; } /* Recieve the data */ if (count == (length - 2)) { value = i2c_do_read(obj, 1); } else if ((length >= 3) && (count == (length - 3))) { value = i2c_do_read(obj, 2); } else { value = i2c_do_read(obj, 0); } data[count] = (char)value; } } else if (length == 2) { /* Set MR3 WAIT bit is 1 */ REG(MR3.UINT32) |= MR3_WAIT; /* dummy read */ value = REG(DRR.UINT32); /* wait for it to arrive */ status = i2c_wait_RDRF(obj); if (status != 0) { i2c_set_err_noslave(obj); return I2C_ERROR_NO_SLAVE; } i2c_set_MR3_NACK(obj); data[count] = (char)REG(DRR.UINT32); count++; } else { /* length == 1 */ /* Set MR3 WAIT bit is 1 */; REG(MR3.UINT32) |= MR3_WAIT; i2c_set_MR3_NACK(obj); /* dummy read */ value = REG(DRR.UINT32); } /* wait for it to arrive */ status = i2c_wait_RDRF(obj); if (status != 0) { i2c_set_err_noslave(obj); return I2C_ERROR_NO_SLAVE; } /* If not repeated start, send stop. */ if (stop) { (void)i2c_set_STOP(obj); /* RIICnDRR read */ value = (REG(DRR.UINT32) & 0xFF); data[count] = (char)value; /* RIICnMR3.WAIT = 0 */ REG(MR3.UINT32) &= ~MR3_WAIT; (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); } else { (void)i2c_restart(obj); /* RIICnDRR read */ value = (REG(DRR.UINT32) & 0xFF); data[count] = (char)value; /* RIICnMR3.WAIT = 0 */ REG(MR3.UINT32) &= ~MR3_WAIT; (void)i2c_wait_START(obj); /* SR2.START = 0 */ REG(SR2.UINT32) &= ~SR2_START; } } else { /* If not repeated start, send stop. */ if (stop) { (void)i2c_set_STOP(obj); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); } else { (void)i2c_restart(obj); (void)i2c_wait_START(obj); /* SR2.START = 0 */ REG(SR2.UINT32) &= ~SR2_START; } } return length; } int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { int cnt; int status; /* There is a STOP condition for last processing */ if (obj->last_stop_flag != 0) { status = i2c_start(obj); if (status != 0) { i2c_set_err_noslave(obj); return I2C_ERROR_BUS_BUSY; } } obj->last_stop_flag = stop; /* Send Slave address */ status = i2c_do_write(obj, address); if (status != 0) { i2c_set_err_noslave(obj); return I2C_ERROR_NO_SLAVE; } /* Wait send end */ status = i2c_wait_TEND(obj); if ((status != 0) || ((REG(SR2.UINT32) & SR2_NACKF) != 0)) { /* Slave sends NACK */ i2c_set_err_noslave(obj); return I2C_ERROR_NO_SLAVE; } /* Send Write data */ for (cnt=0; cnt<length; cnt++) { status = i2c_do_write(obj, data[cnt]); if(status != 0) { i2c_set_err_noslave(obj); return cnt; } else { /* Wait send end */ status = i2c_wait_TEND(obj); if ((status != 0) || ((REG(SR2.UINT32) & SR2_NACKF) != 0)) { /* Slave sends NACK */ i2c_set_err_noslave(obj); return I2C_ERROR_NO_SLAVE; } } } /* If not repeated start, send stop. */ if (stop) { (void)i2c_set_STOP(obj); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); } else { (void)i2c_restart(obj); (void)i2c_wait_START(obj); /* SR2.START = 0 */ REG(SR2.UINT32) &= ~SR2_START; } return length; } void i2c_reset(i2c_t *obj) { (void)i2c_set_STOP(obj); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); } int i2c_byte_read(i2c_t *obj, int last) { int status; int data; data = i2c_do_read(obj, last); /* wait for it to arrive */ status = i2c_wait_RDRF(obj); if (status != 0) { i2c_set_SR2_NACKF_STOP(obj); return I2C_ERROR_NO_SLAVE; } return data; } int i2c_byte_write(i2c_t *obj, int data) { int ack = 0; int status; int timeout = 0; status = i2c_do_write(obj, (data & 0xFF)); if (status != 0) { i2c_set_SR2_NACKF_STOP(obj); } else { while (((i2c_status(obj) & SR2_RDRF) == 0) && ((i2c_status(obj) & SR2_TEND) == 0)) { timeout++; if (timeout >= WAIT_TIMEOUT) { return ack; } } /* check ACK/NACK */ if ((REG(SR2.UINT32) & SR2_NACKF) != 0) { /* NACK */ i2c_set_SR2_NACKF_STOP(obj); } else { ack = 1; } } return ack; } void i2c_slave_mode(i2c_t *obj, int enable_slave) { if (enable_slave != 0) { REG(SER.UINT32) |= SER_SAR0E; // only slave addr 0 is enabled } else { REG(SER.UINT32) &= ~SER_SAR0E; // no slave addr enabled } } int i2c_slave_receive(i2c_t *obj) { int status; int retval; status = (REG(SR1.UINT8[0]) & SR1_AAS0); status |= (REG(CR2.UINT8[0]) & CR2_TRS) >> 4; switch(status) { case 0x01: /* the master is writing to this slave */ retval = 3; break; case 0x02: /* the master is writing to all slave */ retval = 2; break; case 0x03: /* the master has requested a read from this slave */ retval = 1; break; default : /* no data */ retval = 0; break; } return retval; } int i2c_slave_read(i2c_t *obj, char *data, int length) { int timeout = 0; int count; int break_flg = 0; if(length <= 0) { return 0; } for (count = 0; ((count < (length + 1)) && (break_flg == 0)); count++) { /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while (((i2c_status(obj) & SR2_STOP) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) { if ((i2c_status(obj) & SR2_STOP) != 0) { break_flg = 1; break; } timeout ++; if (timeout >= WAIT_TIMEOUT) { return -1; } } if (break_flg == 0) { if (count == 0) { /* dummy read */ (void)REG(DRR.UINT32); } else { data[count - 1] = (char)(REG(DRR.UINT32) & 0xFF); } } } if (break_flg == 0) { (void)i2c_wait_STOP(obj); } else { if ((i2c_status(obj) & SR2_RDRF) != 0) { if (count <= 1) { /* fail safe */ /* dummy read */ (void)REG(DRR.UINT32); } else { data[count - 2] = (char)(REG(DRR.UINT32) & 0xFF); } } } /* SR2.STOP = 0 */ REG(SR2.UINT32) &= ~SR2_STOP; return (count - 1); } int i2c_slave_write(i2c_t *obj, const char *data, int length) { int count = 0; int status = 0; if(length <= 0) { return 0; } while ((count < length) && (status == 0)) { status = i2c_do_write(obj, data[count]); if(status == 0) { /* Wait send end */ status = i2c_wait_TEND(obj); if ((status != 0) || ((count < (length - 1)) && ((REG(SR2.UINT32) & SR2_NACKF) != 0))) { /* NACK */ break; } } count++; } /* dummy read */ (void)REG(DRR.UINT32); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); return count; } void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) { REG(SAR0.UINT32) = (address & 0xfffffffe); }