F1C100S >> Assembly

TWI(I2C)


參考資料:
1. pdf
2. lichee
3. mangopi_r
4. allwinner
5. i2c-sunxi.c

I2C0腳位

I2C0_SCKPE11
I2C0_SDAPE12



暫存器


TWI速度計算

PLL = 24MHz*N*K/M

0x80041800:
  K = 1
  M = 1
  N = 24

PLL_PERIPH = 24MHz*25 = 600MHz
AHB_CLK = PLL_PERIPH/(AHB_PRE_DIV*AHB_CLK_DIV_RATIO) = 600MHz/(3*1) = 200MHz
APB_CLK = AHB_CLK/APB_CLK_RATIO = 200MHz/2 = 100MHz

0x00003180:
  AHB_PRE_DIV = 3
  APB_CLK_RATIO = 2
  AHB_CLK_DIV_RATIO = 1

CLK_N = 3
CLK_M = 2
TWI = 100MHz/(2^CLK_N)*(CLK_M+1)*10 = 100MHz/240 = 416KHz ~= 400KHz

傳送步驟:
1. 設定I2C_START(M_STA)
2. 寫入I2C_DATA(TWI_DATA_REG)
3. 清除INTF(INT_FLAG)
4. 設定I2C_STOP(M_STP)
5. 清除INTF(INT_FLAG)
6. 等待I2C BUS閒置(STAT=0xf8)

Code Status

0x00: Bus error
0x08: START condition transmitted
0x10: Repeated START condition transmitted
0x18: Address + Write bit transmitted, ACK received
0x20: Address + Write bit transmitted, ACK not received
0x28: Data byte transmitted in master mode, ACK received
0x30: Data byte transmitted in master mode, ACK not received
0x38: Arbitration lost in address or data byte
0x40: Address + Read bit transmitted, ACK received
0x48: Address + Read bit transmitted, ACK not received
0x50: Data byte received in master mode, ACK transmitted
0x58: Data byte received in master mode, not ACK transmitted
0x60: Slave address + Write bit received, ACK transmitted
0x68: Arbitration lost in address as master, slave address + Write bit received, ACK transmitted
0x70: General Call address received, ACK transmitted
0x78: Arbitration lost in address as master, General Call address received, ACK transmitted
0x80: Data byte received after slave address received, ACK transmitted
0x88: Data byte received after slave address received, not ACK transmitted
0x90: Data byte received after General Call received, ACK transmitted
0x98: Data byte received after General Call received, not ACK transmitted
0xA0: STOP or repeated START condition received in slave mode
0xA8: Slave address + Read bit received, ACK transmitted
0xB0: Arbitration lost in address as master, slave address + Read bit received, ACK transmitted
0xB8: Data byte transmitted in slave mode, ACK received
0xC0: Data byte transmitted in slave mode, ACK not received
0xC8: Last byte transmitted in slave mode, ACK received
0xD0: Second Address byte + Write bit transmitted, ACK received
0xD8: Second Address byte + Write bit transmitted, ACK not received
0xF8: No relevant status information, INT_FLAG=0

main.s

  .global _start
   
  .equiv CCU_BASE,   0x01c20000
  .equiv GPIO_BASE,  0x01c20800
  .equiv TWI0_BASE,  0x01c27000
  
  .equiv PLL_PERIPH_CTRL_REG,   0x0028
  .equiv AHB_APB_HCLKC_CFG_REG, 0x0054
  .equiv BUS_CLK_GATING_REG2,   0x0068
  .equiv BUS_SOFT_RST_REG2,     0x02d0
 
  .equiv PE,        (0x24 * 4)
  .equiv PORT_CFG0, 0x00
  .equiv PORT_CFG1, 0x04
  .equiv PORT_PUL0, 0x1c

  .equiv TWI_ADDR,  0x00
  .equiv TWI_XADDR, 0x04
  .equiv TWI_DATA,  0x08
  .equiv TWI_CNTR,  0x0c
  .equiv TWI_STAT,  0x10
  .equiv TWI_CCR,   0x14
  .equiv TWI_SRST,  0x18
  .equiv TWI_EFR,   0x1c
  .equiv TWI_LCR,   0x20
  
  .equiv SSD1306_ADDRESS,             0x78
  .equiv SSD1306_LCDWIDTH,            128
  .equiv SSD1306_LCDHEIGHT,           32
  .equiv SSD1306_SETCONTRAST,         0x81
  .equiv SSD1306_DISPLAYALLOW_RESUME, 0xa4
  .equiv SSD1306_DISPLAYALLOW,        0xa5
  .equiv SSD1306_NORMALDISPLAY,       0xa6
  .equiv SSD1306_INVERTDISPLAY,       0xa7
  .equiv SSD1306_DISPLAYOFF,          0xae
  .equiv SSD1306_DISPLAYON,           0xaf
  .equiv SSD1306_SETDISPLAYOFFSET,    0xd3
  .equiv SSD1306_SETCOMPINS,          0xda
  .equiv SSD1306_SETVCOMDETECT,       0xdb
  .equiv SSD1306_SETDISPLAYCLOCKDIV,  0xd5
  .equiv SSD1306_SETPRECHARGE,        0xd9
  .equiv SSD1306_SETMULTIPLEX,        0xa8
  .equiv SSD1306_SETLOWCOLUMN,        0x00
  .equiv SSD1306_SETHIGHCOLUMN,       0x10
  .equiv SSD1306_SETSTARTLINE,        0x40
  .equiv SSD1306_MEMORYMODE,          0x20
  .equiv SSD1306_COLUMNADDR,          0x21
  .equiv SSD1306_PAGEADDR,            0x22
  .equiv SSD1306_COMSCANINC,          0xc0
  .equiv SSD1306_COMSCANDEC,          0xc8
  .equiv SSD1306_SEGREMAP,            0xa0
  .equiv SSD1306_CHARGEPUMP,          0x8d
  .equiv SSD1306_EXTERNALVCC,         0x01
  .equiv SSD1306_SWITCHCAPVCC,        0x02
  
  .arm
  .text
_start:
  .long 0xea000016
  .byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
  .long 0, __spl_size
  .byte 'S', 'P', 'L', 2
  .long 0, 0
  .long 0, 0, 0, 0, 0, 0, 0, 0
  .long 0, 0, 0, 0, 0, 0, 0, 0
  
_vector:
  b reset
  b .
  b .
  b .
  b .
  b .
  b .
  b .
  
reset:
  ldr r0, =CCU_BASE
  ldr r1, =0x80041800
  str r1, [r0, #PLL_PERIPH_CTRL_REG]
  ldr r1, =0x00003180
  str r1, [r0, #AHB_APB_HCLKC_CFG_REG]
  ldr r1, =(1 << 20) | (1 << 16)
  str r1, [r0, #BUS_CLK_GATING_REG2]
  str r1, [r0, #BUS_SOFT_RST_REG2]

  ldr r0, =GPIO_BASE
  ldr r1, =0x33000
  str r1, [r0, #(PE + PORT_CFG1)]
  ldr r1, =0x01400000
  str r1, [r0, #(PE + PORT_PUL0)]
 
  ldr r0, =TWI0_BASE
  ldr r1, =(2 << 3) | (3 << 0)
  str r1, [r0, #TWI_CCR]
  ldr r1, =1
  str r1, [r0, #TWI_SRST]
0:
  ldr r1, [r0, #TWI_SRST]
  cmp r1, #0
  bne 0b
  ldr r1, =(1 << 6)
  str r1, [r0, #TWI_CNTR]

  ldr r0, =SSD1306_DISPLAYOFF
  bl i2c_cmd
  ldr r0, =SSD1306_SETDISPLAYCLOCKDIV
  bl i2c_cmd
  ldr r0, =0x80
  bl i2c_cmd
  ldr r0, =SSD1306_SETMULTIPLEX
  bl i2c_cmd
  ldr r0, =0x1F
  bl i2c_cmd
  ldr r0, =SSD1306_SETDISPLAYOFFSET
  bl i2c_cmd
  ldr r0, =0x00
  bl i2c_cmd
  ldr r0, =SSD1306_SETSTARTLINE
  bl i2c_cmd
  ldr r0, =SSD1306_CHARGEPUMP
  bl i2c_cmd
  ldr r0, =0x14
  bl i2c_cmd
  ldr r0, =SSD1306_MEMORYMODE
  bl i2c_cmd
  ldr r0, =0x00
  bl i2c_cmd
  ldr r0, =SSD1306_SEGREMAP | 0x01
  bl i2c_cmd
  ldr r0, =SSD1306_COMSCANDEC
  bl i2c_cmd
  ldr r0, =SSD1306_SETCOMPINS
  bl i2c_cmd
  ldr r0, =0x02
  bl i2c_cmd
  ldr r0, =SSD1306_SETCONTRAST
  bl i2c_cmd
  ldr r0, =0x8f
  bl i2c_cmd
  ldr r0, =SSD1306_SETPRECHARGE
  bl i2c_cmd
  ldr r0, =0xf1
  bl i2c_cmd
  ldr r0, =SSD1306_SETVCOMDETECT
  bl i2c_cmd
  ldr r0, =0x40
  bl i2c_cmd
  ldr r0, =SSD1306_DISPLAYALLOW_RESUME
  bl i2c_cmd
  ldr r0, =SSD1306_NORMALDISPLAY
  bl i2c_cmd
  ldr r0, =SSD1306_DISPLAYON
  bl i2c_cmd
  ldr r0, =SSD1306_COLUMNADDR
  bl i2c_cmd
  ldr r0, =0
  bl i2c_cmd
  ldr r0, =SSD1306_LCDWIDTH-1
  bl i2c_cmd
  ldr r0, =SSD1306_PAGEADDR
  bl i2c_cmd
  ldr r0, =0
  bl i2c_cmd
  ldr r0, =(SSD1306_LCDHEIGHT/8)-1
  bl i2c_cmd

  ldr r4, =512
0:
  ldr r0, =0xff
  bl i2c_dat
  subs r4, #1
  bne 0b
  
main:
  b main

i2c_clr_intf:
  push {r4, lr}
  ldr r4, =TWI0_BASE
  ldr r1, [r4, #TWI_CNTR]
  bic r1, #0x08
  str r1, [r4, #TWI_CNTR]
  pop {r4, pc}

i2c_cmd:
  push {r4, lr}
  ldr r4, =TWI0_BASE
  ldr r1, [r4, #TWI_CNTR]
  orr r1, #(1 << 5)
  str r1, [r4, #TWI_CNTR]
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0x08
  bne 0b
  
  ldr r1, =SSD1306_ADDRESS
  str r1, [r4, #TWI_DATA]
  bl i2c_clr_intf 
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0x18
  bne 0b
  
  ldr r1, =0x00
  str r1, [r4, #TWI_DATA]
  bl i2c_clr_intf 
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0x28
  bne 0b
  
  str r0, [r4, #TWI_DATA]
  bl i2c_clr_intf 
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0x28
  bne 0b
  
  ldr r1, [r4, #TWI_CNTR]
  orr r1, #(1 << 4)
  str r1, [r4, #TWI_CNTR]
  bl i2c_clr_intf
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0xf8
  bne 0b
  pop {r4, pc}

i2c_dat:
  push {r4, lr}
  ldr r4, =TWI0_BASE
  ldr r1, [r4, #TWI_CNTR]
  orr r1, #(1 << 5)
  str r1, [r4, #TWI_CNTR]
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0x08
  bne 0b
  
  ldr r1, =SSD1306_ADDRESS
  str r1, [r4, #TWI_DATA]
  bl i2c_clr_intf 
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0x18
  bne 0b
  
  ldr r1, =0x40
  str r1, [r4, #TWI_DATA]
  bl i2c_clr_intf 
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0x28
  bne 0b
  
  str r0, [r4, #TWI_DATA]
  bl i2c_clr_intf 
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0x28
  bne 0b
  
  ldr r1, [r4, #TWI_CNTR]
  orr r1, #(1 << 4)
  str r1, [r4, #TWI_CNTR]
  bl i2c_clr_intf
0:
  ldr r1, [r4, #TWI_STAT]
  cmp r1, #0xf8
  bne 0b
  pop {r4, pc}
  .end

完成


返回上一頁