ATmega128 SPI W25Q64 EEPROM 제어하기 -2

2019. 7. 29. 16:28임베디드/ATmega128

이제 EEPROM에 데이터를 쓰고 읽으려고 한다. 바이트 단위로 read, write를 하면 다음 제어신호를 위해 5ms를 기다려야 한는 단점이 있다. 바이트 단위 대신 page 단위로 기록하면 한 번에 훨씬 많은 데이터를 기록할 수 있다

 

페이지는 경계가 존재한다. 즉 경계에 도달하면 다음 주소로 넘어가는 것이 아니라 페이지의 첫 시작 주소로 넘어오게 된다. 따라서 페이지가 시작하는 주소부터 write를 시작하는 것이 좋다

 

 

제어하려는 w25q64는 256바이트 크기의 페이지로 이뤄졌다. w25q64는 64M-bit로 8M-byte로 32768*256 = 8M-byte가 나오게 된다. 다음 명령어로 page write 제어를 할 수 있다. 256개를 한 번에 쓰는 것이므로 명령어와 주소를 입력한 후 총 256개의 데이터를 전달하면 된다

 

코드를 작성하기 전에, 반드시 Timing 요구 사항을 확인해야 한다. 아래 표를 보면 쓰기 명령 전에는 반드시 5ms를 기다려야만 한다. 기다리는 시간은 SS핀을 Low로 내리기 전 대기하는 시간이다

 

 

1. 쓰기 명령을 하기 위해서는 반드시 Write_enable을 해야만 한다. "06h" 명령어를 전달하면 된다

 

 

2.  Write_enable이 잘 됐는지 상태 레지스터를 검사해야 한다. 05h를 전달한 후 다음 바이트에 1번 비트인 WEL을 검사해서 확인할 수 있다

 

 

 

3. Page program을 통해 Write를 할 것인데, 데이터시트를 잘 읽어보면 해당 명령어를 실행하기 전에 해야할 일들이 있다

 

1) Page program을 할 부분에 대해서 사전에 erase를 해야만 한다

2) Write Enable이 되어있어야 한다

3) 그 후 "02h" 명령어를 전달해서 페이지만큼 쓰게 된다

 

 

3-1) Sector-Erase를 하기 위해선 먼저 Timing 요구를 보게 되면, 최대 400ms를 기다려야만 한다

 

 

그리고 4KB 단위로 지우게 되는데, 현재 예제는 256바이트만 쓰고 읽을 것이므로 0번지에서 한 번만 실행할 것이다

 

3-2) 2번 과정과 같다

 

3-3) "02h" 명령어를 전달해서 페이지 단위로 256바이트를 한 번에 쓸 수 있다

 

4. 읽기 과정을 실행한다

 

 

 

/*
* w25q64.c
*
* Created: 2019-07-14 오전 4:16:22
* Author: yeong
*/
#include "w25q64.h"
/** @brief: initialize the ss pin
*/
void w25q_ss_pin_init(void)
{
W25Q_CONTROL_DDR |= (1<<W25Q_SS_PIN); // Set as output
w25q_ss_pin_drive(LOGIC_HIGH);
}
/** @brief: drives the ss pin
*/
void w25q_ss_pin_drive(uint8_t high)
{
if(high)
{
W25Q_CONTROL_PORT |= (1<<W25Q_SS_PIN);
}
else
{
W25Q_CONTROL_PORT &= ~(1<<W25Q_SS_PIN);
}
}
/** @brief: return the manufacturer ID
*/
char w25q_read_manufacturer_id(void)
{
w25q_ss_pin_drive(LOGIC_LOW);
spi_transmit(0x90);
spi_transmit(0x00);
spi_transmit(0x00);
spi_transmit(0x00);
uint8_t man_id = spi_transmit(0x00);
spi_transmit(0x00);
w25q_ss_pin_drive(LOGIC_HIGH);
return man_id;
}
/** @brief: return the device ID
*/
char w25q_read_device_id(void)
{
w25q_ss_pin_drive(LOGIC_LOW);
spi_transmit(0x90);
spi_transmit(0x00);
spi_transmit(0x00);
spi_transmit(0x00);
spi_transmit(0x00);
uint8_t dev_id = spi_transmit(0x00);
w25q_ss_pin_drive(LOGIC_HIGH);
return dev_id;
}
void w25q_write_enable(void)
{
w25q_ss_pin_drive(LOGIC_LOW);
spi_transmit(0x06);
w25q_ss_pin_drive(LOGIC_HIGH);
}
void w25q_write_disable(void)
{
w25q_ss_pin_drive(LOGIC_LOW);
spi_transmit(0x04);
w25q_ss_pin_drive(LOGIC_HIGH);
}
void w25q_page_write(uint32_t addr, uint8_t *data, uint32_t size)
{
uint8_t cmd[3];
cmd[0] = (addr >> 16) & 0xFF;
cmd[1] = (addr >> 8) & 0xFF;
cmd[2] = addr & 0xFF;
_delay_ms(10);
w25q_write_enable();
_delay_ms(10);
w25q_ss_pin_drive(LOGIC_LOW);
_delay_ms(10);
spi_transmit(0x02);
spi_transmit(cmd[0]);
spi_transmit(cmd[1]);
spi_transmit(cmd[2]);
for(int i=0; i<size; i++) {
spi_transmit(data[i]);
}
w25q_ss_pin_drive(LOGIC_HIGH);
while(getstatus());
}
uint8_t w25q_read(uint32_t addr)
{
uint8_t ret;
uint8_t cmd[3];
cmd[0] = (addr >> 16) & 0xFF;
cmd[1] = (addr >> 8) & 0xFF;
cmd[2] = addr & 0xFF;
w25q_ss_pin_drive(LOGIC_LOW);
spi_transmit(0x03);
spi_transmit(cmd[0]);
spi_transmit(cmd[1]);
spi_transmit(cmd[2]);
ret = spi_transmit(0x00);
w25q_ss_pin_drive(LOGIC_HIGH);
while(getstatus());
return ret;
}
uint8_t getstatus(void) {
uint8_t ret;
w25q_ss_pin_drive(LOGIC_LOW);
spi_transmit(0x05);
ret = spi_transmit(0x00);
w25q_ss_pin_drive(LOGIC_HIGH);
return (ret & 0x01);
}
uint8_t is_write_enable(void) {
uint8_t ret;
w25q_ss_pin_drive(LOGIC_LOW);
spi_transmit(0x05);
ret = spi_transmit(0x00);
w25q_ss_pin_drive(LOGIC_HIGH);
return (ret & 0x02);
}
void erase_block(uint32_t addr)
{
uint8_t cmd[3];
cmd[0] = (addr >> 16) & 0xFF;
cmd[1] = (addr >> 8) & 0xFF;
cmd[2] = addr & 0xFF;
_delay_ms(5);
w25q_write_enable();
_delay_ms(500);
w25q_ss_pin_drive(LOGIC_LOW);
_delay_ms(5);
spi_transmit(0x20);
spi_transmit(cmd[0]);
spi_transmit(cmd[1]);
spi_transmit(cmd[2]);
w25q_ss_pin_drive(LOGIC_HIGH);
}
view raw eeprom.c hosted with ❤ by GitHub
/*
* w25q64_readwrite.c
*
* Created: 2019-07-28 오후 4:47:14
* Author : yeong
*/
#define F_CPU 16000000UL
#include <util/delay.h>
#include <avr/io.h>
#include "uart.h"
#include "spi.h"
#include "w25q64.h"
uint8_t wData[0x100];
uint8_t rData[0x100];
int main(void)
{
spi_init();
uart0_init();
// CS init
w25q_ss_pin_init();
for(int i=0; i<0x100; i++) {
wData[i] = i;
}
erase_block(0);
_delay_ms(500);
w25q_page_write(0, wData, 0x100);
_delay_ms(5);
for(int i=0; i<0x100; i++) {
rData[i] = w25q_read(i);
printf("%02X:%d\r\n", i, rData[i]);
_delay_ms(100);
}
while (1)
{
}
}
view raw main.c hosted with ❤ by GitHub