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); | |
} |
/* | |
* 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) | |
{ | |
} | |
} |

'임베디드 > ATmega128' 카테고리의 다른 글
Atmel Studio7 prinf float (0) | 2019.08.04 |
---|---|
ATmega128 SPI W25Q64 EEPROM 제어하기 -3 (0) | 2019.07.29 |
ATmega128 SPI W25Q64 EEPROM 제어하기 -1 (0) | 2019.07.14 |
ATmega128 적외선 리모콘으로 수신기 제어하기 (1) | 2019.07.13 |
ATmega128 I2C 1602 텍스트 LCD 코드 (5) | 2019.07.11 |