Miyoo >> Assembly
SPI(NOR Flash)
參考資料:
1. pdf
2. lichee
3. mangopi_r
4. allwinner
SPI0腳位
| SPI0_CLK | PC0 |
|---|---|
| SPI0_CS | PC1 |
| SPI0_MISO | PC2 |
| SPI0_MOSI | PC3 |

暫存器

初始步驟:
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
完成