Miyoo >> Assembly

SPI(NOR Flash)


參考資料:
1. pdf
2. lichee
3. mangopi_r
4. allwinner

SPI0腳位

SPI0_CLKPC0
SPI0_CSPC1
SPI0_MISOPC2
SPI0_MOSIPC3



暫存器


初始步驟:
1. 設定SPI Mode為Master
2. 設定DHB模式(避免接收多餘資料)
3. 設定CS_Level為Low
4. 設定CS_Owner為SPI Controller
5. 設定SPI CDR1為50MHz

傳送、接收步驟:
1. 清除RX、TX FIFO(FCR_REG)
2. 設定TXRX全部數量(MBC_REG)
3. 設定TX數量(MTC_REG)
4. 設定TX數量(BCC_REG)
5. 開始傳送接收(TCR_REG.XCH)
6. 等待結束後,從RXD提取資料

main.s

  .global _start
 
  .equiv SPI0_BASE,             0x01c05000
  .equiv CCU_BASE,              0x01c20000
  .equiv PIO_BASE,              0x01c20800
  .equiv UART1_BASE,            0x01c25400
   
  .equiv PLL_PERIPH_CTRL_REG,   0x0028
  .equiv AHB_APB_HCLKC_CFG_REG, 0x0054
  .equiv BUS_CLK_GATING_REG0,   0x0060
  .equiv BUS_CLK_GATING_REG2,   0x0068
  .equiv BUS_SOFT_RST_REG0,     0x02c0
  .equiv BUS_SOFT_RST_REG2,     0x02d0
  
  .equiv PA,                    (0x24 * 0)
  .equiv PC,                    (0x24 * 2)
  .equiv PE,                    (0x24 * 4)
  .equiv PIO_CFG0,              0x0000
  .equiv PIO_DATA,              0x0010

  .equiv UART_RBR,              0x0000
  .equiv UART_DLL,              0x0000
  .equiv UART_DLH,              0x0004
  .equiv UART_IER,              0x0004
  .equiv UART_IIR,              0x0008
  .equiv UART_LCR,              0x000c
  .equiv UART_MCR,              0x0010
  .equiv UART_USR,              0x007c
  
  .equiv SPI_GCR,               0x0004
  .equiv SPI_TCR,               0x0008
  .equiv SPI_IER,               0x0010
  .equiv SPI_ISR,               0x0014
  .equiv SPI_FCR,               0x0018
  .equiv SPI_FSR,               0x001c
  .equiv SPI_WCR,               0x0020
  .equiv SPI_CCR,               0x0024
  .equiv SPI_MBC,               0x0030
  .equiv SPI_MTC,               0x0034
  .equiv SPI_BCC,               0x0038
  .equiv SPI_TXD,               0x0200
  .equiv SPI_RXD,               0x0300

  .equiv CMD_PAGE_PROGRAM,      0x02
  .equiv CMD_WRIRE_ENABLE,      0x06
  .equiv CMD_WRITE_DISABLE,     0x04
  .equiv CMD_READ_STATUS_R1,    0x05
  .equiv CMD_READ_STATUS_R2,    0x35
  .equiv CMD_READ_DATA,         0x03
  .equiv CMD_FAST_READ,         0x0b
  .equiv CMD_SECTOR_ERASE,      0x20
  .equiv CMD_CHIP_ERASE,        0xc7
  .equiv CMD_READ_UNIQUE_ID,    0x4b
  .equiv CMD_JEDEC_ID,          0x9f
 
  .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:
  bl ccu_init
  bl spi_init
  bl uart_init

  bl spi_read_jid
  bl spi_read_uid

  ldr r0, =0
  ldr r1, =64
  bl spi_read_data
  bl uart_buf
  
  ldr r0, =0
  bl spi_erase_sector

  ldr r0, =0
  ldr r1, =64
  bl spi_read_data
  bl uart_buf
  
  ldr r1, =64
  ldr r2, =spi_buf
  mov r3, #0
0:
  strb r3, [r2]
  add r2, #1
  add r3, #1
  subs r1, #1
  bne 0b

  ldr r0, =0
  ldr r1, =64
  bl spi_write_data
  
  ldr r0, =0
  ldr r1, =64
  bl spi_read_data
  bl uart_buf
  b .
   
ccu_init:
  push {r4, lr}
  ldr r4, =CCU_BASE
  ldr r1, =0x80041800
  str r1, [r4, #PLL_PERIPH_CTRL_REG]
  ldr r1, =0x00003180
  str r1, [r4, #AHB_APB_HCLKC_CFG_REG]
  pop {r4, pc}

spi_init:
  push {r4, lr}
  ldr r4, =CCU_BASE
  ldr r1, [r4, #BUS_CLK_GATING_REG0]
  orr r1, #(1 << 20)
  str r1, [r4, #BUS_CLK_GATING_REG0]

  ldr r1, [r4, #BUS_SOFT_RST_REG0]
  orr r1, #(1 << 20)
  str r1, [r4, #BUS_SOFT_RST_REG0]
  
  ldr r0, =PIO_BASE
  ldr r1, [r0, #(PC + PIO_CFG0)]
  ldr r2, =0xffff
  bic r1, r2
  ldr r2, =0x2222
  orr r1, r2
  str r1, [r0, #(PC + PIO_CFG0)]

  ldr r4, =SPI0_BASE
  ldr r1, =(1 << 1) | (1 << 0)
  str r1, [r4, #SPI_GCR]
  ldr r1, =(1 << 2) | (1 << 8)
  str r1, [r4, #SPI_TCR]
  ldr r1, =(1 << 8)
  str r1, [r4, #SPI_CCR]
  ldr r2, =(1 << 31) | (1 << 15)
  str r2, [r4, #SPI_FCR]
0:
  ldr r1, [r4, #SPI_FCR]
  tst r1, r2
  bne 0b
  pop {r4, pc}

uart_init:
  push {r4, lr}
  ldr r4, =CCU_BASE
  ldr r1, [r4, #BUS_CLK_GATING_REG2]
  orr r1, #(1 << 21)
  str r1, [r4, #BUS_CLK_GATING_REG2]

  ldr r1, [r4, #BUS_SOFT_RST_REG2]
  orr r1, #(1 << 21)
  str r1, [r4, #BUS_SOFT_RST_REG2]
  
  ldr r4, =PIO_BASE
  ldr r1, [r4, #(PA + PIO_CFG0)]
  bic r1, #0xff00
  orr r1, #0x5500
  str r1, [r4, #(PA + PIO_CFG0)]

  ldr r4, =UART1_BASE
  ldr r1, =0x00
  str r1, [r4, #UART_IER]
  ldr r1, =0xf7
  str r1, [r4, #UART_IIR]
  ldr r1, =0x00
  str r1, [r4, #UART_MCR]
  ldr r1, [r4, #UART_LCR]
  orr r1, #(1 << 7)
  str r1, [r4, #UART_LCR]
  ldr r1, =54
  str r1, [r4, #UART_DLL]
  ldr r1, =0x00
  str r1, [r4, #UART_DLH]
  ldr r1, [r4, #UART_LCR]
  bic r1, #(1 << 7)
  str r1, [r4, #UART_LCR]
  ldr r1, [r4, #UART_LCR]
  bic r1, #0x1f
  orr r1, #0x03
  str r1, [r4, #UART_LCR]
  pop {r4, pc}
 
uart_byte:
  push {r4, lr}
  ldr r4, =UART1_BASE
0:
  ldr r1, [r4, #UART_USR]
  tst r1, #(1 << 1)
  beq 0b
  strb r0, [r4, #UART_RBR]
  pop {r4, pc}

uart_4byte:
  push {r4, lr}
  mov r4, r0
  lsr r0, #24
  bl uart_byte
 
  mov r0, r4
  lsr r0, #16
  bl uart_byte
   
  mov r0, r4
  lsr r0, #8
  bl uart_byte
   
  mov r0, r4
  bl uart_byte
  pop {r4, pc}

uart_buf:
  push {r4, r5, lr}
  ldr r4, =64
  ldr r5, =spi_buf
0:
  ldrb r0, [r5]
  bl uart_byte
  add r5, #1
  subs r4, #1
  bne 0b
  pop {r4, r5, pc}

spi_read_jid:
  push {r4, lr}
  ldr r4, =SPI0_BASE
  ldr r1, =5
  str r1, [r4, #SPI_MBC]
  ldr r1, =1
  str r1, [r4, #SPI_MTC]
  ldr r1, =1
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_JEDEC_ID
  strb r1, [r4, #SPI_TXD]

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b
 
  ldr r2, =spi_jid
  ldr r3, =4
0:
  ldrb r1, [r4, #SPI_RXD]
  strb r1, [r2]
  add r2, #1
  subs r3, #1
  bne 0b
  pop {r4, pc}

spi_read_uid:
  push {r4, lr}
  ldr r4, =SPI0_BASE
  ldr r1, =13
  str r1, [r4, #SPI_MBC]
  ldr r1, =1
  str r1, [r4, #SPI_MTC]
  ldr r1, =1
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_READ_UNIQUE_ID
  strb r1, [r4, #SPI_TXD]

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b
 
  ldr r2, =spi_uid
  ldr r3, =12
0:
  ldrb r1, [r4, #SPI_RXD]
  strb r1, [r2]
  add r2, #1
  subs r3, #1
  bne 0b
  pop {r4, pc}

spi_read_data:
  push {r4, r5, lr}
  ldr r4, =SPI0_BASE
  mov r5, r1

  add r1, #4
  str r1, [r4, #SPI_MBC]
  ldr r1, =4
  str r1, [r4, #SPI_MTC]
  ldr r1, =4
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_READ_DATA
  strb r1, [r4, #SPI_TXD]

  mov r1, r0
  lsr r0, #16
  strb r0, [r4, #SPI_TXD]

  mov r0, r1
  lsr r0, #8
  strb r0, [r4, #SPI_TXD]

  mov r0, r1
  strb r0, [r4, #SPI_TXD]

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b

  ldr r2, =spi_buf
  mov r3, r5
0:
  ldrb r1, [r4, #SPI_RXD]
  strb r1, [r2]
  add r2, #1
  subs r3, #1
  bne 0b
  pop {r4, r5, pc}

spi_write_enable:
  push {r4, lr}
  ldr r4, =SPI0_BASE
  ldr r1, =1
  str r1, [r4, #SPI_MBC]
  ldr r1, =1
  str r1, [r4, #SPI_MTC]
  ldr r1, =1
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_WRIRE_ENABLE
  strb r1, [r4, #SPI_TXD]

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b
  pop {r4, pc}

spi_write_disable:
  push {r4, lr}
  ldr r4, =SPI0_BASE
  ldr r1, =1
  str r1, [r4, #SPI_MBC]
  ldr r1, =1
  str r1, [r4, #SPI_MTC]
  ldr r1, =1
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_WRITE_DISABLE
  strb r1, [r4, #SPI_TXD]

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b
  pop {r4, pc}

spi_is_busy:
  push {r4, lr}
  ldr r4, =SPI0_BASE
  ldr r1, =2
  str r1, [r4, #SPI_MBC]
  ldr r1, =1
  str r1, [r4, #SPI_MTC]
  ldr r1, =1
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_READ_STATUS_R1
  strb r1, [r4, #SPI_TXD]

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b
 
  ldrb r0, [r4, #SPI_RXD]
  and r0, #1
  pop {r4, pc}

spi_erase_sector:
  push {r4, lr}
  mov r4, r0
  bl spi_write_enable
  mov r0, r4

  ldr r4, =SPI0_BASE
  ldr r1, =4
  str r1, [r4, #SPI_MBC]
  ldr r1, =4
  str r1, [r4, #SPI_MTC]
  ldr r1, =4
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_SECTOR_ERASE
  strb r1, [r4, #SPI_TXD]

  mov r1, r0
  lsr r0, #16
  strb r0, [r4, #SPI_TXD]

  mov r0, r1
  lsr r0, #8
  strb r0, [r4, #SPI_TXD]

  mov r0, r1
  strb r0, [r4, #SPI_TXD]

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b

0:
  bl spi_is_busy
  cmp r0, #0
  bne 0b
  pop {r4, pc}

spi_erase_all:
  push {r4, lr}
  bl spi_write_enable

  ldr r4, =SPI0_BASE
  ldr r1, =1
  str r1, [r4, #SPI_MBC]
  ldr r1, =1
  str r1, [r4, #SPI_MTC]
  ldr r1, =1
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_CHIP_ERASE
  strb r1, [r4, #SPI_TXD]

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b

0:
  bl spi_is_busy
  cmp r0, #0
  bne 0b
  pop {r4, pc}

spi_write_data:
  push {r4, r5, lr}
  mov r4, r0
  mov r5, r1
  bl spi_write_enable

0:
  bl spi_is_busy
  cmp r0, #0
  bne 0b
  
  mov r0, r4
  mov r1, r5

  ldr r4, =SPI0_BASE
  add r1, #4
  str r1, [r4, #SPI_MBC]
  str r1, [r4, #SPI_MTC]
  str r1, [r4, #SPI_BCC]

  ldrb r1, =CMD_PAGE_PROGRAM
  strb r1, [r4, #SPI_TXD]

  mov r1, r0
  lsr r0, #16
  strb r0, [r4, #SPI_TXD]

  mov r0, r1
  lsr r0, #8
  strb r0, [r4, #SPI_TXD]

  mov r0, r1
  strb r0, [r4, #SPI_TXD]

  ldr r2, =spi_buf
  mov r3, r5
0:
  ldrb r1, [r2]
  strb r1, [r4, #SPI_TXD]
  add r2, #1
  subs r3, #1
  bne 0b

  ldr r1, [r4, #SPI_TCR]
  orr r1, #(1 << 31)
  str r1, [r4, #SPI_TCR]
0:
  ldr r1, [r4, #SPI_TCR]
  tst r1, #(1 << 31)
  bne 0b

0:
  bl spi_is_busy
  cmp r0, #0
  bne 0b
  pop {r4, r5, pc}

  .data
spi_jid: .skip 4
spi_uid: .skip 12
spi_buf: .skip 64
  .end

完成


返回上一頁