完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一 . rk3288 android7.1.2 u-boot i2c
1.1byte register addr 1)写时序 slave addr(1byte) + register addr(1byte)+ Wvlaue(1byte) 2)读时序 slave addr(1byte) + register addr(1byte)+ (slave addr(1byte)+1)+ Rvlaue(1byte) 2.2byte register addr 1)写时序 slave addr(1byte) + register addr(H8+L8 2byte)+ Wvlaue(1byte) 2)读时序 slave addr(1byte) + register addr(H8+L8 2byte)+ (slave addr(1byte)+1)+ Rvlaue(1byte) 注意:start 以及ACK 并未标出,而且读时序有restart 3.在根目录u-boot/drivers/i2c/rk_i2c.c ,为了根据时序的不同改写code 而不影响原本code 的调用,建议重写读写函数如下: static int rk_i2c_read1(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, uchar *buf, uint b_len); static int rk_i2c_write1(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, uchar *buf, uint b_len); int i2c_read_x(uchar chip, uint addr, int alen, uchar *buf, int len); int i2c_write_x(uchar chip, uint addr, int alen, uchar *buf, int len); 4.整个rk_i2c.c 如下: /* * (C) Copyright 2008-2016 Fuzhou Rockchip Electronics Co., Ltd * Peter, Software Engineering, * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #define RKI2C_VERSION "1.3" /* i2c debug information config */ #define RKI2C_DEBUG_INFO #ifdef RKI2C_DEBUG_INFO #define i2c_info(format, arg...) printf(format, ##arg) #else #define i2c_info(format, arg...) #endif /* register io */ #define i2c_writel(val, addr) writel(val, addr) #define i2c_readl(addr) readl(addr) /* i2c timerout */ #define I2C_TIMEOUT_US 100000 // 100000us = 100ms #define I2C_RETRY_COUNT 3 /* i2c error return code */ #define I2C_OK 0 #define I2C_ERROR_TIMEOUT -1 #define I2C_ERROR_NOACK -2 #define I2C_ERROR_IO -3 /* rk i2c fifo max transfer bytes */ #define RK_I2C_FIFO_SIZE 32 /* rk i2c device register size */ #define RK_I2C_REGISTER_SIZE 3 #define RK_CEIL(x, y) ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; }) #define I2C_ADAP_SEL_BIT(nr) ((nr) + 11) #define I2C_ADAP_SEL_MASK(nr) ((nr) + 27) /* Control register */ #define I2C_CON 0x000 #define I2C_CON_EN (1 << 0) #define I2C_CON_MOD(mod) ((mod) << 1) #define I2C_MODE_TX 0x00 #define I2C_MODE_TRX 0x01 #define I2C_MODE_RX 0x02 #define I2C_MODE_RRX 0x03 #define I2C_CON_MASK (3 << 1) #define I2C_CON_START (1 << 3) #define I2C_CON_STOP (1 << 4) #define I2C_CON_LASTACK (1 << 5) #define I2C_CON_ACTACK (1 << 6) /* Clock dividor register */ #define I2C_CLKDIV 0x004 #define I2C_CLKDIV_VAL(divl, divh) (((divl) & 0xffff) | (((divh) << 16) & 0xffff0000)) /* the slave address accessed for master rx mode */ #define I2C_MRXADDR 0x008 #define I2C_MRXADDR_SET(vld, addr) (((vld) << 24) | (addr)) /* the slave register address accessed for master rx mode */ #define I2C_MRXRADDR 0x00c #define I2C_MRXRADDR_SET(vld, raddr) (((vld) << 24) | (raddr)) /* master tx count */ #define I2C_MTXCNT 0x010 /* master rx count */ #define I2C_MRXCNT 0x014 /* interrupt enable register */ #define I2C_IEN 0x018 #define I2C_BTFIEN (1 << 0) #define I2C_BRFIEN (1 << 1) #define I2C_MBTFIEN (1 << 2) #define I2C_MBRFIEN (1 << 3) #define I2C_STARTIEN (1 << 4) #define I2C_STOPIEN (1 << 5) #define I2C_NAKRCVIEN (1 << 6) /* interrupt pending register */ #define I2C_IPD 0x01c #define I2C_BTFIPD (1 << 0) #define I2C_BRFIPD (1 << 1) #define I2C_MBTFIPD (1 << 2) #define I2C_MBRFIPD (1 << 3) #define I2C_STARTIPD (1 << 4) #define I2C_STOPIPD (1 << 5) #define I2C_NAKRCVIPD (1 << 6) #define I2C_IPD_ALL_CLEAN 0x7f /* finished count */ #define I2C_FCNT 0x020 /* I2C tx data register */ #define I2C_TXDATA_BASE 0X100 /* I2C rx data register */ #define I2C_RXDATA_BASE 0x200 struct rk_i2c { uint32_t regs; unsigned int speed; }; #ifdef CONFIG_I2C_MULTI_BUS static struct rk_i2c rki2c_base[I2C_BUS_MAX] = { { .regs = (uint32_t)RKIO_I2C0_BASE, 0 }, { .regs = (uint32_t)RKIO_I2C1_BASE, 0 }, { .regs = (uint32_t)RKIO_I2C2_BASE, 0 }, { .regs = (uint32_t)RKIO_I2C3_BASE, 0 }, { .regs = (uint32_t)RKIO_I2C4_BASE, 0 }, { .regs = (uint32_t)RKIO_I2C5_BASE, 0 }, { .regs = (uint32_t)RKIO_I2C6_BASE, 0 }, { .regs = (uint32_t)RKIO_I2C7_BASE, 0 } }; #endif static uint g_i2c_online_bus = I2C_BUS_MAX; static inline void *rk_i2c_get_base(void) { if (g_i2c_online_bus >= I2C_BUS_MAX) { printf("I2C bus error, PLS set i2c bus first!n"); return (void *)NULL; } if (rki2c_base[g_i2c_online_bus].regs == 0) { printf("I2C base register error, PLS check i2c config!n"); return (void *)NULL; } return (void *)&rki2c_base[g_i2c_online_bus]; } static inline void rk_i2c_iomux(eI2C_ch_t bus_id) { rk_iomux_config(RK_I2C0_IOMUX + bus_id); } static inline void rk_i2c_get_div(int div, int *divh, int *divl) { if (div % 2 == 0) { *divh = div / 2; *divl = div / 2; } else { *divh = RK_CEIL(div, 2); *divl = div / 2; } } /* SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1) * SCL = PCLK / SCLK Divisor * i2c_rate = PCLK */ static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32 scl_rate) { uint32 i2c_rate; int div, divl, divh; if (i2c->speed == scl_rate) { return ; } /* First get i2c rate from pclk */ i2c_rate = rkclk_get_i2c_clk(g_i2c_online_bus); div = RK_CEIL(i2c_rate, scl_rate * 8) - 2; if (div < 0) { divh = divl = 0; } else { rk_i2c_get_div(div, &divh, &divl); } i2c_writel(I2C_CLKDIV_VAL(divl, divh), i2c->regs + I2C_CLKDIV); i2c->speed = scl_rate; i2c_info("rk_i2c_set_clk: i2c rate = %d, scl rate = %dn", i2c_rate, scl_rate); i2c_info("set i2c clk div = %d, divh = %d, divl = %dn", div, divh, divl); i2c_info("set clk(I2C_CLKDIV: 0x%08x)n", i2c_readl(i2c->regs + I2C_CLKDIV)); } static int rk_i2c_init(int speed) { struct rk_i2c *i2c = (struct rk_i2c *)rk_i2c_get_base(); if (i2c == NULL) { return -1; } i2c_info("rk_i2c_init: I2C bus = %dn", g_i2c_online_bus); rk_i2c_iomux(g_i2c_online_bus); rk_i2c_set_clk(i2c, speed); return 0; } static void rk_i2c_show_regs(struct rk_i2c *i2c) { #ifdef RKI2C_DEBUG_INFO uint i; i2c_info("I2C_CON: 0x%08xn", i2c_readl(i2c->regs + I2C_CON)); i2c_info("I2C_CLKDIV: 0x%08xn", i2c_readl(i2c->regs + I2C_CLKDIV)); i2c_info("I2C_MRXADDR: 0x%08xn", i2c_readl(i2c->regs + I2C_MRXADDR)); i2c_info("I2C_MRXRADDR: 0x%08xn", i2c_readl(i2c->regs + I2C_MRXRADDR)); i2c_info("I2C_MTXCNT: 0x%08xn", i2c_readl(i2c->regs + I2C_MTXCNT)); i2c_info("I2C_MRXCNT: 0x%08xn", i2c_readl(i2c->regs + I2C_MRXCNT)); i2c_info("I2C_IEN: 0x%08xn", i2c_readl(i2c->regs + I2C_IEN)); i2c_info("I2C_IPD: 0x%08xn", i2c_readl(i2c->regs + I2C_IPD)); i2c_info("I2C_FCNT: 0x%08xn", i2c_readl(i2c->regs + I2C_FCNT)); for (i = 0; i < 8; i ++) { i2c_info("I2C_TXDATA%d: 0x%08xn", i, i2c_readl(i2c->regs + I2C_TXDATA_BASE + i * 4)); } for (i = 0; i < 8; i ++) { i2c_info("I2C_RXDATA%d: 0x%08xn", i, i2c_readl(i2c->regs + I2C_RXDATA_BASE + i * 4)); } #endif } static int rk_i2c_send_start_bit(struct rk_i2c *i2c) { int TimeOut = I2C_TIMEOUT_US; i2c_info("I2c Send Start bit.n"); i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD); i2c_writel(I2C_CON_EN | I2C_CON_START, i2c->regs + I2C_CON); i2c_writel(I2C_STARTIEN, i2c->regs + I2C_IEN); while (TimeOut--) { if (i2c_readl(i2c->regs + I2C_IPD) & I2C_STARTIPD) { i2c_writel(I2C_STARTIPD, i2c->regs + I2C_IPD); break; } udelay(1); } if (TimeOut <= 0) { printf("I2C Send Start Bit Timeoutn"); rk_i2c_show_regs(i2c); return I2C_ERROR_TIMEOUT; } return I2C_OK; } static int rk_i2c_send_stop_bit(struct rk_i2c *i2c) { int TimeOut = I2C_TIMEOUT_US; i2c_info("I2c Send Stop bit.n"); i2c_writel(I2C_IPD_ALL_CLEAN, i2c->regs + I2C_IPD); i2c_writel(I2C_CON_EN | I2C_CON_STOP, i2c->regs + I2C_CON); i2c_writel(I2C_CON_STOP, i2c->regs + I2C_IEN); while (TimeOut--) { if (i2c_readl(i2c->regs + I2C_IPD) & I2C_STOPIPD) { i2c_writel(I2C_STOPIPD, i2c->regs + I2C_IPD); break; } udelay(1); } if (TimeOut <= 0) { printf("I2C Send Stop Bit Timeoutn"); rk_i2c_show_regs(i2c); return I2C_ERROR_TIMEOUT; } return I2C_OK; } static inline void rk_i2c_disable(struct rk_i2c *i2c) { i2c_writel(0, i2c->regs + I2C_CON); } static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, uchar *buf, uint b_len) { int err = I2C_OK; int TimeOut = I2C_TIMEOUT_US; uchar *pbuf = buf; uint bytes_remain_len = b_len; uint bytes_tranfered_len = 0; uint words_tranfered_len = 0; uint con = 0; uint rxdata; uint i, j; i2c_info("rk_i2c_read: chip = %x, reg = %x, r_len = %d, b_len = %dn", chip, reg, r_len, b_len); err = rk_i2c_send_start_bit(i2c); if (err != I2C_OK) { return err; } i2c_writel(I2C_MRXADDR_SET(1, chip << 1 | 1), i2c->regs + I2C_MRXADDR); if (r_len == 0) { i2c_writel(0, i2c->regs + I2C_MRXRADDR); } else if (r_len < 4) { i2c_writel(I2C_MRXRADDR_SET(r_len, reg), i2c->regs + I2C_MRXRADDR); } else { printf("I2C Read: addr len %d not supportedn", r_len); return I2C_ERROR_IO; } while (bytes_remain_len) { if (bytes_remain_len > RK_I2C_FIFO_SIZE) { con = I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TRX); bytes_tranfered_len = 32; } else { con = I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TRX) | I2C_CON_LASTACK; bytes_tranfered_len = bytes_remain_len; } words_tranfered_len = RK_CEIL(bytes_tranfered_len, 4); i2c_writel(con, i2c->regs + I2C_CON); i2c_writel(bytes_tranfered_len, i2c->regs + I2C_MRXCNT); i2c_writel(I2C_MBRFIEN | I2C_NAKRCVIEN, i2c->regs + I2C_IEN); TimeOut = I2C_TIMEOUT_US; while (TimeOut--) { if (i2c_readl(i2c->regs + I2C_IPD) & I2C_NAKRCVIPD) { i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD); err = I2C_ERROR_NOACK; } if (i2c_readl(i2c->regs + I2C_IPD) & I2C_MBRFIPD) { i2c_writel(I2C_MBRFIPD, i2c->regs + I2C_IPD); break; } udelay(1); } if (TimeOut <= 0) { printf("I2C Read Data Timeoutn"); err = I2C_ERROR_TIMEOUT; rk_i2c_show_regs(i2c); goto i2c_exit; } for (i = 0; i < words_tranfered_len; i++) { rxdata = i2c_readl(i2c->regs + I2C_RXDATA_BASE + i * 4); i2c_info("I2c Read RXDATA[%d] = 0x%xn", i, rxdata); for (j = 0; j < 4; j++) { if ((i * 4 + j) == bytes_tranfered_len) { break; } *pbuf++ = (rxdata >> (j * 8)) & 0xff; } } bytes_remain_len -= bytes_tranfered_len; i2c_info("I2C Read bytes_remain_len %dn", bytes_remain_len); } i2c_exit: // Send stop bit rk_i2c_send_stop_bit(i2c); // Disable Controller rk_i2c_disable(i2c); return err; } static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, uchar *buf, uint b_len) { int err = I2C_OK; int TimeOut = I2C_TIMEOUT_US; uchar *pbuf = buf; uint bytes_remain_len = b_len + r_len + 1; uint bytes_tranfered_len = 0; uint words_tranfered_len = 0; uint txdata; uint i, j; i2c_info("rk_i2c_write: chip = %x, reg = %x, r_len = %d, b_len = %dn", chip, reg, r_len, b_len); err = rk_i2c_send_start_bit(i2c); if (err != I2C_OK) { return err; } while (bytes_remain_len) { if (bytes_remain_len > RK_I2C_FIFO_SIZE) { bytes_tranfered_len = 32; } else { bytes_tranfered_len = bytes_remain_len; } words_tranfered_len = RK_CEIL(bytes_tranfered_len, 4); for (i = 0; i < words_tranfered_len; i++) { txdata = 0; for (j = 0; j < 4; j++) { if ((i * 4 + j) == bytes_tranfered_len) { break; } if (i == 0 && j == 0) { txdata |= (chip << 1); } else if (i == 0 && j <= r_len) { txdata |= (reg & (0xff << ((j - 1) * 8))) << 8; printf("I2c Write reg = 0x%xn", (reg & (0xff << ((j - 1) * 8))) << 8); } else { txdata |= (*pbuf++)<<(j * 8); } i2c_writel(txdata, i2c->regs + I2C_TXDATA_BASE + i * 4); } i2c_info("I2c Write TXDATA[%d] = 0x%xn", i, txdata); printf("I2c Write TXDATA[%d] = 0x%xn", i, txdata); } i2c_writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), i2c->regs + I2C_CON); i2c_writel(bytes_tranfered_len, i2c->regs + I2C_MTXCNT); i2c_writel(I2C_MBTFIEN | I2C_NAKRCVIEN, i2c->regs + I2C_IEN); TimeOut = I2C_TIMEOUT_US; while (TimeOut--) { if (i2c_readl(i2c->regs + I2C_IPD) & I2C_NAKRCVIPD) { i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD); err = I2C_ERROR_NOACK; } if (i2c_readl(i2c->regs + I2C_IPD) & I2C_MBTFIPD) { i2c_writel(I2C_MBTFIPD, i2c->regs + I2C_IPD); break; } udelay(1); } if (TimeOut <= 0) { printf("I2C Write Data Timeoutn"); err = I2C_ERROR_TIMEOUT; rk_i2c_show_regs(i2c); goto i2c_exit; } bytes_remain_len -= bytes_tranfered_len; i2c_info("I2C Write bytes_remain_len %dn", bytes_remain_len); } i2c_exit: // Send stop bit rk_i2c_send_stop_bit(i2c); // Disable Controller rk_i2c_disable(i2c); return err; } #ifdef CONFIG_I2C_MULTI_BUS unsigned int i2c_get_bus_num(void) { return g_i2c_online_bus; } int i2c_set_bus_num(unsigned bus_idx) { i2c_info("i2c_set_bus_num: I2C bus = %dn", bus_idx); if (bus_idx >= I2C_BUS_MAX) { printf("i2c_set_bus_num: I2C bus error!n"); return -1; } g_i2c_online_bus = bus_idx; return 0; } #endif |
|
|
|
static int rk_i2c_read1(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, uchar *buf, uint b_len)
{ int err = I2C_OK; int TimeOut = I2C_TIMEOUT_US; uchar *pbuf = buf,tmp[4]; uint bytes_remain_len = b_len; uint bytes_tranfered_len = 0; uint words_tranfered_len = 0; uint con = 0; uint rxdata; uint i, j; i2c_info("rk_i2c_read1: chip = %x, reg = %x, r_len = %d, b_len = %dn", chip, reg, r_len, b_len); err = rk_i2c_send_start_bit(i2c); if (err != I2C_OK) { return err; } tmp[0] = (uchar)(reg & 0xff); tmp[1] = (uchar)((reg >> 8) & 0xff); tmp[2] = (uchar)((reg >> 16) & 0xff); tmp[3] = (uchar)((reg >> 24) & 0xff); if(r_len == 2) { reg = (tmp[0] << 8) + tmp[1]; } else if(r_len == 3){ reg = (tmp[0] << 16) + (tmp[1] << 8) + tmp[2]; } else if(r_len == 4){ reg = (tmp[0] << 24) + (tmp[1] << 16) + (tmp[2] << 8) + tmp[3]; } else if(r_len > 4){ i2c_info("I2C Read1: addr len %d not supportedn", r_len); } else{ ; } i2c_writel(I2C_MRXADDR_SET(1, chip << 1 | 1), i2c->regs + I2C_MRXADDR); if (r_len == 0) { i2c_writel(0, i2c->regs + I2C_MRXRADDR); } else if (r_len == 1) { i2c_writel(I2C_MRXRADDR_SET(r_len, reg), i2c->regs + I2C_MRXRADDR); } else if (r_len == 2) { i2c_writel(I2C_MRXRADDR_SET(r_len + 1, reg), i2c->regs + I2C_MRXRADDR); } else if (r_len == 3) { i2c_writel(I2C_MRXRADDR_SET(r_len + 4, reg), i2c->regs + I2C_MRXRADDR); } else { i2c_info("I2C Read1: addr len %d not supportedn", r_len); return I2C_ERROR_IO; } while (bytes_remain_len) { if (bytes_remain_len > RK_I2C_FIFO_SIZE) { con = I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TRX); bytes_tranfered_len = 32; } else { con = I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TRX) | I2C_CON_LASTACK; bytes_tranfered_len = bytes_remain_len; } words_tranfered_len = RK_CEIL(bytes_tranfered_len, 4); i2c_writel(con, i2c->regs + I2C_CON); i2c_writel(bytes_tranfered_len, i2c->regs + I2C_MRXCNT); i2c_writel(I2C_MBRFIEN | I2C_NAKRCVIEN, i2c->regs + I2C_IEN); TimeOut = I2C_TIMEOUT_US; while (TimeOut--) { if (i2c_readl(i2c->regs + I2C_IPD) & I2C_NAKRCVIPD) { i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD); err = I2C_ERROR_NOACK; } if (i2c_readl(i2c->regs + I2C_IPD) & I2C_MBRFIPD) { i2c_writel(I2C_MBRFIPD, i2c->regs + I2C_IPD); break; } udelay(1); } if (TimeOut <= 0) { i2c_info("I2C Read1 Data Timeoutn"); err = I2C_ERROR_TIMEOUT; rk_i2c_show_regs(i2c); goto i2c_exit; } for (i = 0; i < words_tranfered_len; i++) { rxdata = i2c_readl(i2c->regs + I2C_RXDATA_BASE + i * 4); i2c_info("I2c Read1 RXDATA[%d] = 0x%xn", i, rxdata); for (j = 0; j < 4; j++) { if ((i * 4 + j) == bytes_tranfered_len) { break; } *pbuf++ = (rxdata >> (j * 8)) & 0xff; } } bytes_remain_len -= bytes_tranfered_len; i2c_info("I2C Read1 bytes_remain_len %dn", bytes_remain_len); } i2c_exit: // Send stop bit rk_i2c_send_stop_bit(i2c); // Disable Controller rk_i2c_disable(i2c); return err; } static int rk_i2c_write1(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, uchar *buf, uint b_len) { int err = I2C_OK; int TimeOut = I2C_TIMEOUT_US; uchar *pbuf = buf,tmp[4]; uint bytes_remain_len = b_len + r_len + 1; uint bytes_tranfered_len = 0; uint words_tranfered_len = 0; uint txdata; uint i, j; i2c_info("rk_i2c_write1: chip = %x, reg = %x, r_len = %d, b_len = %dn", chip, reg, r_len, b_len); err = rk_i2c_send_start_bit(i2c); if (err != I2C_OK) { return err; } tmp[0] = (uchar)(reg & 0xff); tmp[1] = (uchar)((reg >> 8) & 0xff); tmp[2] = (uchar)((reg >> 16) & 0xff); tmp[3] = (uchar)((reg >> 24) & 0xff); if(r_len == 2) { reg = (tmp[0] << 8) + tmp[1]; } else if(r_len == 3){ reg = (tmp[0] << 16) + (tmp[1] << 8) + tmp[2]; } else if(r_len == 4){ reg = (tmp[0] << 24) + (tmp[1] << 16) + (tmp[2] << 8) + tmp[3]; } else if(r_len > 4){ i2c_info("I2C Read1: addr len %d not supportedn", r_len); } else{ ; } while (bytes_remain_len) { if (bytes_remain_len > RK_I2C_FIFO_SIZE) { bytes_tranfered_len = 32; } else { bytes_tranfered_len = bytes_remain_len; } words_tranfered_len = RK_CEIL(bytes_tranfered_len, 4); for (i = 0; i < words_tranfered_len; i++) { txdata = 0; for (j = 0; j < 4; j++) { if ((i * 4 + j) == bytes_tranfered_len) { break; } if (i == 0 && j == 0) { txdata |= (chip << 1); i2c_info("I2c Write1 txdata = 0x%xn", txdata); } else if (i == 0 && j <= r_len) { txdata |= (reg & (0xff << ((j - 1) * 8))) << 8; i2c_info("I2c Write1 txdata = 0x%xn", txdata); } else { txdata |= (*pbuf++)<<(j * 8); i2c_info("I2c Write1 txdata = 0x%xn", txdata); } i2c_writel(txdata, i2c->regs + I2C_TXDATA_BASE + i * 4); } i2c_info("I2c Write1 TXDATA[%d] = 0x%xn", i, txdata); } i2c_writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), i2c->regs + I2C_CON); i2c_writel(bytes_tranfered_len, i2c->regs + I2C_MTXCNT); i2c_writel(I2C_MBTFIEN | I2C_NAKRCVIEN, i2c->regs + I2C_IEN); TimeOut = I2C_TIMEOUT_US; while (TimeOut--) { if (i2c_readl(i2c->regs + I2C_IPD) & I2C_NAKRCVIPD) { i2c_writel(I2C_NAKRCVIPD, i2c->regs + I2C_IPD); err = I2C_ERROR_NOACK; } if (i2c_readl(i2c->regs + I2C_IPD) & I2C_MBTFIPD) { i2c_writel(I2C_MBTFIPD, i2c->regs + I2C_IPD); break; } udelay(1); } if (TimeOut <= 0) { i2c_info("I2C Write1 Data Timeoutn"); err = I2C_ERROR_TIMEOUT; rk_i2c_show_regs(i2c); goto i2c_exit; } bytes_remain_len -= bytes_tranfered_len; i2c_info("I2C Write1 bytes_remain_len %dn", bytes_remain_len); } i2c_exit: // Send stop bit rk_i2c_send_stop_bit(i2c); // Disable Controller rk_i2c_disable(i2c); return err; } /* * i2c_read - Read from i2c memory * @chip: target i2c address * @addr: address to read from * @alen: * @buffer: buffer for read data * @len: no of bytes to be read * * Read from i2c memory. */ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) { struct rk_i2c *i2c = (struct rk_i2c *)rk_i2c_get_base(); if (i2c == NULL) { return -1; } if ((buf == NULL) && (len != 0)) { printf("i2c_read: buf == NULLn"); return -2; } return rk_i2c_read(i2c, chip, addr, alen, buf, len); } |
|
|
|
/*
* i2c_write - Write to i2c memory * @chip: target i2c address * @addr: address to read from * @alen: * @buffer: buffer for read data * @len: num of bytes to be read * * Write to i2c memory. */ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) { struct rk_i2c *i2c = (struct rk_i2c *)rk_i2c_get_base(); if (i2c == NULL) { return -1; } if ((buf == NULL) && (len != 0)) { printf("i2c_write: buf == NULLn"); return -2; } return rk_i2c_write(i2c, chip, addr, alen, buf, len); } /* * i2c_read - Read from i2c memory * @chip: target i2c address * @addr: address to read from * @alen: * @buffer: buffer for read data * @len: no of bytes to be read * * Read from i2c memory. */ int i2c_read_x(uchar chip, uint addr, int alen, uchar *buf, int len) { struct rk_i2c *i2c = (struct rk_i2c *)rk_i2c_get_base(); if (i2c == NULL) { return -1; } if ((buf == NULL) && (len != 0)) { printf("i2c_read: buf == NULLn"); return -2; } return rk_i2c_read1(i2c, chip, addr, alen, buf, len); } /* * i2c_write - Write to i2c memory * @chip: target i2c address * @addr: address to read from * @alen: * @buffer: buffer for read data * @len: num of bytes to be read * * Write to i2c memory. */ int i2c_write_x(uchar chip, uint addr, int alen, uchar *buf, int len) { struct rk_i2c *i2c = (struct rk_i2c *)rk_i2c_get_base(); if (i2c == NULL) { return -1; } if ((buf == NULL) && (len != 0)) { printf("i2c_write: buf == NULLn"); return -2; } return rk_i2c_write1(i2c, chip, addr, alen, buf, len); } /* * Test if a chip at a given address responds (probe the chip) */ int i2c_probe(uchar chip) { struct rk_i2c *i2c = (struct rk_i2c *)rk_i2c_get_base(); i2c_info("i2c_proben"); if (i2c == NULL) { return -1; } return rk_i2c_write(i2c, chip, 0, 0, NULL, 0); } /* * Init I2C Bus */ void i2c_init(int speed, int unused) { i2c_info("i2c_initn"); rk_i2c_init(speed); } /* * Set I2C Speed */ int i2c_set_bus_speed(unsigned int speed) { struct rk_i2c *i2c = (struct rk_i2c *)rk_i2c_get_base(); i2c_info("i2c_set_bus_speedn"); if (i2c == NULL) { return -1; } if (g_i2c_online_bus >= I2C_BUS_MAX) { return -1; } rk_i2c_set_clk(i2c, speed); return 0; } /* * Get I2C Speed */ unsigned int i2c_get_bus_speed(void) { return 0; } int i2c_get_bus_num_fdt(int bus_addr) { int i; for (i = 0; i < ARRAY_SIZE(rki2c_base); i++) { if ((uint32_t)bus_addr == rki2c_base.regs) return i; } printf("%s: Can't find any matched I2C busn", __func__); return -1; } 5.重要code 分析: 1)2bytes register addr 读写时,由于原文件是先送低位后送高位,所以reg addr传进函数,先进行高低位置换: tmp[0] = (uchar)(reg & 0xff); tmp[1] = (uchar)((reg >> 8) & 0xff); tmp[2] = (uchar)((reg >> 16) & 0xff); tmp[3] = (uchar)((reg >> 24) & 0xff); if(r_len == 2) { reg = (tmp[0] << 8) + tmp[1]; } else if(r_len == 3){ reg = (tmp[0] << 16) + (tmp[1] << 8) + tmp[2]; } else if(r_len == 4){ reg = (tmp[0] << 24) + (tmp[1] << 16) + (tmp[2] << 8) + tmp[3]; } else if(r_len > 4){ i2c_info("I2C Read1: addr len %d not supportedn", r_len); } else{ ; } 注意:根据slave device 进行调整,不过一定要注意原code 是先传送的低8位后送高八位!!! 2)2bytes register addr 读时,原code 无法使用(个人认为有误,需要修正): 根据手册可知: /* the slave register address accessed for master rx mode */ #define I2C_MRXRADDR 0x00c #define I2C_MRXRADDR_SET(vld, raddr) (((vld) << 24) | (raddr)) vld 表示位有效: vld = 1 表示sraddlvld address low byte valid vld = 2 表示sraddlvld address middle byte valid vld = 4 表示sraddlvld address high byte valid 因此1byte vld = 1 ,2bytes vld = 3 3bytes vld = 7 i2c_writel(I2C_MRXADDR_SET(1, chip << 1 | 1), i2c->regs + I2C_MRXADDR); if (r_len == 0) { i2c_writel(0, i2c->regs + I2C_MRXRADDR); } else if (r_len == 1) { i2c_writel(I2C_MRXRADDR_SET(r_len, reg), i2c->regs + I2C_MRXRADDR); } else if (r_len == 2) { i2c_writel(I2C_MRXRADDR_SET(r_len + 1, reg), i2c->regs + I2C_MRXRADDR); } else if (r_len == 3) { i2c_writel(I2C_MRXRADDR_SET(r_len + 4, reg), i2c->regs + I2C_MRXRADDR); } else { i2c_info("I2C Read1: addr len %d not supportedn", r_len); return I2C_ERROR_IO; } 按照如上改写,测试读正常,使用示波器观察图形正常 6.读写函数已重写,如何调用上电对slave device 初始化 1)编写头文件rk_i2c.h ,将其放到根目录u-boot/include/ 下 /*opyright (C) ST-Ericsson SA 2009 * * SPDX-License-Identifier: GPL-2.0+ */ #ifndef _RK_I2C_H_ #define _RK_I2C_H_ int i2c_set_bus_num(unsigned bus_idx); void i2c_init(int speed, int unused); int i2c_set_bus_speed(unsigned int speed); int i2c_probe(uchar chip); int i2c_read_x(uchar chip, uint addr, int alen, uchar *buf, int len); int i2c_write_x(uchar chip, uint addr, int alen, uchar *buf, int len); #endif /* _RK_I2C_H_ */ 2)在根目录u-boot/board/rockchip/ 下,在rk32xx.c 文件中添加rk_i2c.h 头文件以及slave device 的init 函数如下: static int xxx_device_i2c(void) { unsigned char a[1]={0x41}; int tmp; i2c_set_bus_num(1); i2c_init(100000, 0); i2c_set_bus_speed(100000); tmp = i2c_probe(0x30); printf("nni2c_probe = %dnn", tmp); printf("nn*****************read/write reg 16bit******************nn"); mdelay(10); i2c_read_x(0x30, 0x1404, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); tmp = a[0] << 8; mdelay(10); i2c_read_x(0x30, 0x1405, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); tmp = tmp + a[0]; printf("nn========================T613 ID = 0x%x==================nn",tmp); mdelay(10); i2c_read_x(0x30, 0x2480, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); i2c_read_x(0x30, 0x2482, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); i2c_read_x(0x30, 0x2484, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); i2c_read_x(0x30, 0x2485, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); a[0] = 0x33; i2c_write_x(0x30, 0x2480, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); a[0] = 0x99; i2c_write_x(0x30, 0x2488, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); a[0] = 0x66; i2c_write_x(0x30, 0x248A, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); printf("nn*****************read/write reg 8bit******************nn"); mdelay(100); i2c_read_x(0x24, 0x84, 1, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); i2c_read_x(0x24, 0x85, 1, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); a[0] = 0x33; i2c_write_x(0x24, 0x80, 1, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); return (0); } 调用顺序: 3)在rk32xx.c 中的int board_late_init(void);函数中调用即可,完整code 如下: /* * (C) Copyright 2008-2015 Fuzhou Rockchip Electronics Co., Ltd * Peter, Software Engineering, <superpeter.cai@gmail.com>. * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include #include //#include #include #include #include #include "../common/config.h" #ifdef CONFIG_OPTEE_CLIENT #include "../common/rkloader/attestation_key.h" #endif enum project_id { TinkerBoardS = 0, TinkerBoard = 7, }; enum pcb_id { SR, ER, PR, }; extern bool force_ums; DECLARE_GLOBAL_DATA_PTR; static ulong get_sp(void) { ulong ret; asm("mov %0, sp" : "=r"(ret) : ); return ret; } void board_lmb_reserve(struct lmb *lmb) { ulong sp; sp = get_sp(); debug("## Current stack ends at 0x%08lx ", sp); /* adjust sp by 64K to be safe */ sp -= 64<<10; lmb_reserve(lmb, sp, gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp); //reserve 48M for kernel & 8M for nand api. lmb_reserve(lmb, gd->bd->bi_dram[0].start, CONFIG_LMB_RESERVE_SIZE); } { int ret = 0; if (StorageInit() == 0) { printf("storage init OK!n"); ret = 0; } else { printf("storage init fail!n"); ret = -1; } return ret; } |
|
|
|
/*****************************************
* Routine: board_init * Description: Early hardware init. *****************************************/ int board_init(void) { /* Set Initial global variables */ gd->bd->bi_arch_number = MACH_TYPE_RK30XX; gd->bd->bi_boot_params = PHYS_SDRAM + 0x88000; return 0; } #ifdef CONFIG_DISPLAY_BOARDINFO /** * Print board information */ int checkboard(void) { puts("Board:tRockchip platform Boardn"); #ifdef CONFIG_SECOND_LEVEL_BOOTLOADER printf("Uboot as second level loadern"); #endif return 0; } #endif #ifdef CONFIG_ARCH_EARLY_INIT_R int arch_early_init_r(void) { debug("arch_early_init_rn"); /* set up exceptions */ interrupt_init(); /* enable exceptions */ enable_interrupts(); /* rk pl330 dmac init */ #ifdef CONFIG_RK_PL330_DMAC rk_pl330_dmac_init_all(); #endif /* CONFIG_RK_PL330_DMAC */ #ifdef CONFIG_RK_PWM_REMOTE RemotectlInit(); #endif return 0; } #endif #define RAMDISK_ZERO_COPY_SETTING "0xffffffff=n " static void board_init_adjust_env(void) { bool change = false; char *s = getenv("bootdelay"); if (s != NULL) { unsigned long bootdelay = 0; bootdelay = simple_strtoul(s, NULL, 16); debug("getenv: bootdelay = %lun", bootdelay); #if (CONFIG_BOOTDELAY <= 0) if (bootdelay > 0) { setenv("bootdelay", simple_itoa(0)); change = true; debug("setenv: bootdelay = 0n"); } #else if (bootdelay != CONFIG_BOOTDELAY) { setenv("bootdelay", simple_itoa(CONFIG_BOOTDELAY)); change = true; debug("setenv: bootdelay = %dn", CONFIG_BOOTDELAY); } #endif } s = getenv("bootcmd"); if (s != NULL) { debug("getenv: bootcmd = %sn", s); if (strcmp(s, CONFIG_BOOTCOMMAND) != 0) { setenv("bootcmd", CONFIG_BOOTCOMMAND); change = true; debug("setenv: bootcmd = %sn", CONFIG_BOOTCOMMAND); } } s = getenv("initrd_high"); if (s != NULL) { debug("getenv: initrd_high = %sn", s); if (strcmp(s, RAMDISK_ZERO_COPY_SETTING) != 0) { setenv("initrd_high", RAMDISK_ZERO_COPY_SETTING); change = true; debug("setenv: initrd_high = %sn", RAMDISK_ZERO_COPY_SETTING); } } if (change) { #ifdef CONFIG_CMD_SAVEENV debug("board init saveenv.n"); saveenv(); #endif } } void u***_current_limit_ctrl(bool unlock_current) { printf("%s: unlock_current = %dn", __func__, unlock_current); if(unlock_current == true) gpio_direction_output(GPIO_BANK6|GPIO_A6, 1); else gpio_direction_output(GPIO_BANK6|GPIO_A6, 0); } |
|
|
|
/*
* * eMMC maskrom mode : GPIO6_A7 (H:disable maskrom, L:enable maskrom) * */ void rk3288_maskrom_ctrl(bool enable_emmc) { printf("%s: enable_emmc = %dn", __func__, enable_emmc); if(enable_emmc == true) gpio_direction_output(GPIO_BANK6|GPIO_A7, 1); else gpio_direction_output(GPIO_BANK6|GPIO_A7, 0); mdelay(10); } void check_force_enter_ums_mode(void) { enum pcb_id pcbid; enum project_id projectid; // enable projectid pull down and set it to input gpio_pull_updown(GPIO_BANK2|GPIO_A1, GPIOPullUp); gpio_pull_updown(GPIO_BANK2|GPIO_A2, GPIOPullUp); gpio_pull_updown(GPIO_BANK2|GPIO_A3, GPIOPullUp); gpio_direction_input(GPIO_BANK2|GPIO_A1); gpio_direction_input(GPIO_BANK2|GPIO_A2); gpio_direction_input(GPIO_BANK2|GPIO_A3); // set pcbid to input gpio_direction_input(GPIO_BANK2|GPIO_B0); // disable SDP pull up/down and set it to input gpio_pull_updown(GPIO_BANK6|GPIO_A5, PullDisable); gpio_direction_input(GPIO_BANK6|GPIO_A5); mdelay(10); // read project id projectid = gpio_get_value(GPIO_BANK2|GPIO_A1) | gpio_get_value(GPIO_BANK2|GPIO_A2)<<1 | gpio_get_value(GPIO_BANK2|GPIO_A3)<<2; // read pcbid pcbid = gpio_get_value(GPIO_BANK2|GPIO_B0) | gpio_get_value(GPIO_BANK2|GPIO_B1)<<1 | gpio_get_value(GPIO_BANK2|GPIO_B2)<<2; // only Tinker Board S and the PR stage PCB has this function if(projectid!=TinkerBoard && pcbid >= ER){ printf("PC event = 0x%xn", gpio_get_value(GPIO_BANK6|GPIO_A5)); if(gpio_get_value(GPIO_BANK6|GPIO_A5) == 1){ // SDP detected, enable EMMC and unlock u*** current limit printf("u*** connected to SDP, force enter ums moden"); force_ums = true; // unlock u*** current limit and re-enable EMMC u***_current_limit_ctrl(true); rk3288_maskrom_ctrl(true); mdelay(10); } } } static int xxx_device_i2c(void) { unsigned char a[1]={0x41}; int tmp; i2c_set_bus_num(1); i2c_init(100000, 0); i2c_set_bus_speed(100000); tmp = i2c_probe(0x30); printf("nni2c_probe = %dnn", tmp); printf("nn*****************read/write reg 16bit******************nn"); mdelay(10); i2c_read_x(0x30, 0x1404, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); tmp = a[0] << 8; mdelay(10); i2c_read_x(0x30, 0x1405, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); tmp = tmp + a[0]; printf("nn========================T613 ID = 0x%x==================nn",tmp); mdelay(10); i2c_read_x(0x30, 0x2480, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); i2c_read_x(0x30, 0x2482, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); i2c_read_x(0x30, 0x2484, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); i2c_read_x(0x30, 0x2485, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); a[0] = 0x33; i2c_write_x(0x30, 0x2480, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); a[0] = 0x99; i2c_write_x(0x30, 0x2488, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); a[0] = 0x66; i2c_write_x(0x30, 0x248A, 2, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); printf("nn*****************read/write reg 8bit******************nn"); mdelay(100); i2c_read_x(0x24, 0x84, 1, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); i2c_read_x(0x24, 0x85, 1, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); mdelay(10); a[0] = 0x33; i2c_write_x(0x24, 0x80, 1, a, 1); printf("nnt613_init = 0x%02xnn", a[0]); return (0); } #ifdef CONFIG_BOARD_LATE_INIT extern char bootloader_ver[24]; int board_late_init(void) { debug("board_late_initn"); board_init_adjust_env(); load_disk_partitions(); debug("rkimage_prepare_fdtn"); rkimage_prepare_fdt(); #ifdef CONFIG_RK_KEY debug("key_initn"); key_init(); #endif #ifdef CONFIG_RK_POWER debug("fixed_initn"); fixed_regulator_init(); debug("pmic_initn"); pmic_init(0); #if defined(CONFIG_POWER_PWM_REGULATOR) debug("pwm_regulator_initn"); pwm_regulator_init(); #endif debug("fg_initn"); fg_init(0); /*fuel gauge init*/ #endif /* CONFIG_RK_POWER */ #if defined(CONFIG_RK_DCF) dram_freq_init(); #endif #ifdef CONFIG_OPTEE_CLIENT load_attestation_key(); #endif debug("idb initn"); //TODO:set those buffers in a better way, and use malloc? rkidb_setup_space(gd->arch.rk_global_buf_addr); /* after setup space, get id block data first */ rkidb_get_idblk_data(); /* Secure boot check after idb data get */ SecureBootCheck(); if (rkidb_get_bootloader_ver() == 0) { printf("n#Boot ver: %sn", bootloader_ver); } char tmp_buf[32]; /* rk sn size 30bytes, zero buff */ memset(tmp_buf, 0, 32); if (rkidb_get_sn(tmp_buf)) { setenv("fbt_sn#", tmp_buf); } debug("fbt prebootn"); board_fbt_preboot(); xxx_device_i2c_i2c(); return 0; } #endif int board_modify_fdt(void) { #if defined(CONFIG_RKCHIP_RK3288) && defined(CONFIG_NORMAL_WORLD) int ret; /* RK3288W HDMI Revision ID is 0x1A */ if (readl(RKIO_HDMI_PHYS + 0x4) == 0x1A) { ret = fdt_setprop_string((void *)gd->fdt_blob, 0, "compatible", "rockchip,rk3288w"); if (ret) { printf("fdt set compatible failed: %dn", ret); return -1; } } #endif return 0; } #ifdef CONFIG_CMD_NET /* * Initializes on-chip ethernet controllers. * to override, implement board_eth_init() */ int board_eth_init(bd_t *bis) { __maybe_unused int rc; debug("board_eth_initn"); #ifdef CONFIG_RK_GMAC char macaddr[6]; char ethaddr[20]; char *env_str = NULL; memset(ethaddr, sizeof(ethaddr), 0); env_str = getenv("ethaddr"); if (rkidb_get_mac_address(macaddr) == true) { sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); printf("mac address: %sn", ethaddr); if (env_str == NULL) setenv ((char *)"ethaddr", (char *)ethaddr); else if (strncmp(env_str, ethaddr, strlen(ethaddr)) != 0) setenv ((char *)"ethaddr", (char *)ethaddr); } else { uint16_t v; v = (rand() & 0xfeff) | 0x0200; macaddr[0] = (v >> 8) & 0xff; macaddr[1] = v & 0xff; v = rand(); macaddr[2] = (v >> 8) & 0xff; macaddr[3] = v & 0xff; v = rand(); macaddr[4] = (v >> 8) & 0xff; macaddr[5] = v & 0xff; sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); if (env_str == NULL) { printf("mac address: %sn", ethaddr); setenv ((char *)"ethaddr", (char *)ethaddr); } else { printf("mac address: %sn", env_str); } } rc = rk_gmac_initialize(bis); if (rc < 0) { printf("rockchip: failed to initialize gmacn"); return rc; } #endif /* CONFIG_RK_GMAC */ return 0; } #endif #ifdef CONFIG_ROCKCHIP_DISPLAY extern void rockchip_display_fixup(void *blob); #endif #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) void ft_board_setup(void *blob, bd_t * bd) { #ifdef CONFIG_ROCKCHIP_DISPLAY rockchip_display_fixup(blob); #endif #ifdef CONFIG_ROCKCHIP #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO) u64 start, size; int offset; if (!gd->uboot_logo) return; start = gd->fb_base; offset = gd->fb_offset; if (offset > 0) size = CONFIG_RK_LCD_SIZE; else size = CONFIG_RK_FB_SIZE; fdt_update_reserved_memory(blob, "rockchip,fb-logo", start, size); #endif #endif } #endif 7.改写完成后重新进行如下操作: echo 对u-boot 进行重新编译,生成新的update.img cd u-boot make cd .. ./mkimage.sh cd RKTools/linux/Linux_Pack_Firmware/rockdev ./collectImages.sh && ./mkupdate.sh echo 在windows 下打开 SpiImageTools.exe 加在update.img,会在当前文件夹下产生bin 档(该工具在源码目录下 RKToolswindows) echo 打开Win32diskImager.exe 将bin 档烧写到SD卡中,然后上电启动RK3288 重新上电后,就会对slave device 进行init 操作。 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
2104 浏览 1 评论
synopsys 的design ware:DW_fpv_div,浮点数除法器,默认32位下,想提升覆盖率(TMAX),如果用功能case去提升覆盖率呢?
2735 浏览 1 评论
RK3588 GStreamer调试四路鱼眼摄像头四宫格显示报错
5514 浏览 1 评论
【飞凌嵌入式OK3576-C开发板体验】RKNN神经网络-YOLO图像识别
254 浏览 0 评论
【飞凌嵌入式OK3576-C开发板体验】SSH远程登录网络配置及CAN通讯
1336 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-29 03:26 , Processed in 0.834533 second(s), Total 81, Slave 64 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号