RaspberrPi project source code
Guo Wenxue
2024-07-06 f67df94069569d193ee2cc8d70dd9747cc2574a4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*********************************************************************************
 *      Copyright:  (C) 2023 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  at24c.c
 *    Description:  This file is AT24Cxx EEPROM code
 *
 *        Version:  1.0.0(10/08/23)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "10/08/23 17:52:00"
 *
 * Pin connection:
 *                 W25QXX       Raspberry Pi 40Pin
 *                   VCC   <--->   Pin#1 (3.3V)
 *                   CS    <--->   Pin#24(CS)
 *                   DO    <--->   Pin#21(MISO)
 *                   GND   <--->   Pin#9 (GND)
 *                   CLK   <--->   Pin#23(SCLK)
 *                   DI    <--->   Pin#19(MOSI)
 *
 * /boot/config.txt:
 *                  dtparam=spi=on
 *
 ********************************************************************************/
 
#ifndef _W25QFLASH_H
#define _W25QFLASH_H
 
#include <stdbool.h>
 
#define _W25QXX_DEBUG                   1
 
/* Flash opcodes. Refer to <<W25Q256JV.pdf>> P26 Table 8.1.2 Instruction Set Table */
#define SPINOR_OP_RDID          0x9f    /* Read JEDEC ID */
#define SPINOR_OP_RDUID         0x4b    /* Read unique ID */
#define SPINOR_OP_WRSR1         0x01    /* Write status register-1 */
#define SPINOR_OP_WRSR2         0x31    /* Write status register-2 */
#define SPINOR_OP_WRSR3         0x11    /* Write status register-3 */
#define SPINOR_OP_BP            0x02    /* Byte program */
#define SPINOR_OP_READ          0x03    /* Read data bytes (low frequency) */
#define SPINOR_OP_WRDI          0x04    /* Write disable */
#define SPINOR_OP_RDSR1         0x05    /* Read status register-1 */
#define SPINOR_OP_RDSR2         0x35    /* Read status register-2 */
#define SPINOR_OP_RDSR3         0x15    /* Read status register-3 */
#define SPINOR_OP_WREN          0x06    /* Write enable */
#define SPINOR_OP_READ_FAST     0x0b    /* Read data bytes (high frequency) */
#define SPINOR_OP_READ_FAST_4B  0x0c    /* Read data bytes (high frequency) */
 
#define SPINOR_OP_CHIP_ERASE    0xc7    /* Erase whole flash chip */
#define SPINOR_OP_BE_4K_4B      0xdc    /* Block erase (64KiB) with 4-Byte Address */
#define SPINOR_OP_BE_4K         0xd8    /* Block erase (64KiB) */
#define SPINOR_OP_SE_4B         0x21    /* Sector erase (4KiB) with 4-Byte Address */
#define SPINOR_OP_SE            0x20    /* Sector erase (4KiB)  */
#define SPINOR_OP_PP_4B         0x12    /* Page Program (up to 256 bytes) with 4-Byte Address */
#define SPINOR_OP_PP            0x02    /* Page program (up to 256 bytes) */
#define SPINOR_OP_SRSTEN        0x66    /* Software Reset Enable */
#define SPINOR_OP_SRST          0x99    /* Software Reset */
 
typedef struct spi_info
{
    int  hspi;      /* SPI device description */
 
    void (*select)(struct spi_info *spi);   /* CS enable function  */
    void (*deselect)(struct spi_info *spi); /* CS disable function */
    void (*xcmd)(struct spi_info *spi, uint8_t command); /* Send a byte command */
    void (*xfer)(struct spi_info *spi, uint8_t *send_buf, uint8_t *recv_buf, int bytes); /* Transmit and Receive N byte */
} spi_info_t;
 
typedef struct flash_info
{
    char            *name;          /* Chip name */
    uint32_t         jedec_id;      /* JEDEC ID, 3 bytes */
    uint64_t         capacity;      /* Chip   size in bytes */
    uint32_t         block_size;    /* Block  size in bytes */
    uint32_t         sector_size;   /* Sector size in bytes */
    uint32_t         page_size;     /* Page   size in bytes */
    uint32_t         n_blocks;      /* Number of blocks */
    uint32_t         n_sectors;     /* Number of sectors */
    uint32_t         n_pages;       /* Number of pages */
} flash_info_t;
 
 
typedef struct spinor_info
{
    spi_info_t      *spi;
    flash_info_t    *flash;
    uint8_t          lock;
} spinor_info_t;
 
 
/* Status registers */
enum
{
    REG_STATUS1,
    REG_STATUS2,
    REG_STATUS3,
    REG_STATUS_MAX,
};
 
/*+-------------------------------+
 *|   SPI Norflash HighLevel API  |
 *+-------------------------------+*/
 
/* SPI Norflash API test function */
extern void spinor_test(void);
 
/* Initial SPI and detect the flash chip */
extern int spinor_init(struct spinor_info *spinor);
 
/* Description:  Erase whole flash chip.
 * Reference  :  P60, 8.2.32 Chip Erase (C7h / 60h)
 */
extern int spinor_erase_chip(struct spinor_info *spinor);
 
/* Description:  Erase blocks by 64KiB,
 * Reference  :  P59, 8.2.31 64KB Block Erase with 4-Byte Address (DCh)
 *  @address is the erase start physical address, which can be not block alignment such as 0x10001.
 *  @size is the erase size, which can be larger than a block such as 4097, and it will erase 2 blocks;
 */
extern int spinor_erase_block(struct spinor_info *spinor, uint32_t address, uint32_t size);
 
/* Description:  Erase sectors by 4KiB
 * Reference  :  P56, 8.2.28 Sector Erase with 4-Byte Address (21h)
 *  @address is the erase start physical address, which can be not sector alignment such as 0x1001.
 *  @size is the erase size, which can be larger than a sector such as 4097, and it will erase 2 sectors;
 */
extern int spinor_erase_sector(struct spinor_info *spinor, uint32_t address, uint32_t size);
 
/* Description:  Page random write by 256B
 *  @addr is the write start physical address, which can be not page alignment such as 0x101.
 *  @size is the write size, which can be larger than a page such as 257, and it will write 2 pages;
 */
extern int spinor_write(struct spinor_info *spinor, uint32_t address, uint8_t *data, uint32_t bytes);
 
/* Description:  The Fast Read instruction can read the entire memory chip.
 * Reference  :  P41, 8.2.13 Fast Read with 4-Byte Address (0Ch)
 *  @address is the read start physical address, which can be not page alignment such as 0x101.
 *  @size is the read size, which can be larger than a page such as 257, and it will read 2 pages;
 */
extern int spinor_read(struct spinor_info *spinor, uint32_t address, uint8_t *buf, uint32_t bytes);
 
/*+-------------------------------+
 *|   SPI Norflash LowLevel API   |
 *+-------------------------------+*/
 
/* Detect the norflash by JEDEC ID */
int spinor_detect_by_jedec(struct spinor_info *spinor);
 
/* Description:  Read the chipset UNIQUE ID.
 * Reference  :  P68, 8.2.40 Read Unique ID Number (4Bh)
 */
int spinor_read_uniqid(struct spi_info *spi, uint8_t *uniq_id);
 
/* Description:  Read the chipset JEDEC ID.
 * Reference  :  P69, 8.2.41 Read JEDEC ID (9Fh)
 */
uint32_t spinor_read_jedecid(struct spi_info *spi);
 
/* Description:  Write Enable
 * Reference  :  P31, 8.2.1 Write Enable (06h)
 */
void spinor_write_enable(struct spi_info *spi);
 
/* Description:  Write Disable
 * Reference  :  P32, 8.2.3 Write Disable (04h)
 */
void spinor_write_disable(struct spi_info *spi);
 
/* Description:  Read Status Register
 * Reference  :  P32, 8.2.4 Read Status Register-1 (05h), Status Register-2 (35h) & Status Register-3 (15h)
 */
uint8_t spinor_read_status_reg(struct spi_info *spi, uint8_t reg);
 
/* Description:  Write Status Register
 * Reference  :  P33, 8.2.5 Write Status Register-1 (01h), Status Register-2 (31h) & Status Register-3 (11h)
 */
void spinor_write_status_reg(struct spi_info *spi, uint8_t reg, uint8_t value);
 
/* Description:  Wait flash program/erase finished by read Status Register for BUSY bit
 * Reference  :  P15, 7.1 Status Registers
 */
void spinor_WaitForWriteEnd(struct spi_info *spi);
 
#endif