单片机常用的总线如i2c、spi、uart等,将其硬件抽象层分离,相关外设在其抽象层上的应用函数接口调用。这样的好处是 :
1、外设的驱动方便移植到任何单片机;
2、外设总线方便移植到其他单片机,只需更改部分寄存器配置;
3、总线调试OK后,调试新的外设程序时,不用重重复复调试总线的程序。
比如:spi总线和eeprom设备分离,假如我这个spi总线要挂其他spi设备(传感器、ADC等),那不需重新写一次总线程序。假设换了一家公司,用了不同单片机,这个eeprom程序可以方便移植到任何单片机。
4、附上25系列(spi)接口eeprom驱动程序,spi函数做了封装,只需调用相关抽象层接口即可,程序方便移植到任何单片机,只需修改相应spi底层接口。没记错的话FM25LXX兼容25系列(spi)的EEPROM,FM24Lxx兼容24系列(i2c)的EEPROM。
//头文件
#ifndef _25XX_H_
#define _25XX_H_
//25xx register
#define REG_READ_COMMAND 0X03
#define REG_WRITE_COMMAND 0X02
#define REG_WRITE_ENABLE 0X06
#define REG_WRITE_DISABLE 0X04
#define REG_READ_STATUS 0X05
#define REG_WRITE_STATUS 0X01
//extern function
extern void ee_25xx_init(void);
extern void ee_25xx_write_bytes(uint16_t write_addr, uint8_t *write_buff, uint16_t write_bytes);
extern void ee_25xx_read_bytes(uint16_t read_addr,uint8_t *read_buff,uint16_t read_bytes);
#endif
//源文件
#include "main.h"
#include "spi.h"
#include "25xx.h"
//module variable
#define EE25XX_PAGE_SIZE 64 //25aa256
struct st_spi_device ee_25xx_spi_dev;
//module function
static uint8_t ee_25xx_wait_busy(void);
//
void ee_25xx_init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//SPI2 cs
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //ÍÆÍìÊä³ö
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //È«Ë«¹¤
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //Ö÷ģʽ
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //data_width
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; //spiʱÖÓ£¬¸ù¾ÝÆ÷¼þËÙ¶ÈÉèÖÃ
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //¸ßλÔÚÇ°
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
//device init
ee_25xx_spi_dev.cs_io.GPIOx = GPIOB;
ee_25xx_spi_dev.cs_io.GPIO_Pin = GPIO_Pin_12;
ee_25xx_spi_dev.data_width = 8;
ee_25xx_spi_dev.SPI = SPI2;
SPI_Cmd(SPI2, ENABLE);
}
//
void ee_25xx_write_enable(uint8_t select)
{
spi_send(&ee_25xx_spi_dev,&select,1);
}
//
void ee_25xx_write_byte(uint16_t write_addr,uint8_t write_data)
{
uint8_t send_buff[3];
ee_25xx_write_enable(REG_WRITE_ENABLE);
send_buff[0] = REG_WRITE_COMMAND;
send_buff[1] = (write_addr>>8)&0xff;
send_buff[2] = write_addr&0xff;
spi_send_then_send(&ee_25xx_spi_dev,send_buff,3,&write_data,1);
ee_25xx_write_enable(REG_WRITE_DISABLE);
}
/**
* @brief 25xx write page
* @param address,buff,size.write_size is not more than device page size,such as 64 bytes for 25aa256.
* @retval None
*/
void ee_25xx_write_page(uint16_t write_addr,uint8_t *write_page_buff,uint8_t write_size)
{
uint8_t send_buff[3];
ee_25xx_write_enable(REG_WRITE_ENABLE);
send_buff[0] = REG_WRITE_COMMAND;
send_buff[1] = (write_addr>>8)&0xff;
send_buff[2] = write_addr&0xff;
spi_send_then_send(&ee_25xx_spi_dev,send_buff,3,write_page_buff,write_size);
ee_25xx_write_enable(REG_WRITE_DISABLE);
}
//
void ee_25xx_write_bytes(uint16_t write_addr, uint8_t *write_buff, uint16_t write_bytes)
{
uint8_t write_current_bytes,page_offset;
uint16_t write_remain,write_current_addr;
uint8_t *pbuff;
//ee_25xx_write_enable(REG_WRITE_ENABLE);
pbuff = write_buff; //²»ÒªÖ±½ÓʹÓÃÐβμÆË㣬ÌرðÊÇÖ¸Õë²Ù×÷
write_remain = write_bytes;
write_current_addr = write_addr;
while(write_remain > 0)
{
page_offset = write_current_addr % EE25XX_PAGE_SIZE; //Á¬Ðøҳд´óС£¬25aa256Ϊ64×Ö½Ú
write_current_bytes = write_remain > (EE25XX_PAGE_SIZE - page_offset) ? (EE25XX_PAGE_SIZE - page_offset) : write_remain;
ee_25xx_write_page(write_current_addr,pbuff, write_current_bytes);
write_remain = write_remain - write_current_bytes;
if(write_remain > 0)
{
pbuff = pbuff + EE25XX_PAGE_SIZE - page_offset;
write_current_addr = write_current_addr + EE25XX_PAGE_SIZE - page_offset;
//Delayms(5);
ee_25xx_wait_busy();//wait free,¸ù¾ÝcpuʱÖÓ¼ÆËãʱ¼ä
}
}
//ee_25xx_write_enable(REG_WRITE_DISABLE);
}
//
void ee_25xx_read_bytes(uint16_t read_addr,uint8_t *read_buff,uint16_t read_bytes)
{
uint8_t send_buff[3];
send_buff[0] = REG_READ_COMMAND;
send_buff[1] = (read_addr>>8)&0xff;
send_buff[2] = read_addr&0xff;
spi_send_then_recv(&ee_25xx_spi_dev,send_buff,3,read_buff,read_bytes);
}
//
void ee_25xx_write_status(uint8_t write_data)
{
u8 send_buff[2];
send_buff[0] = REG_WRITE_STATUS;
send_buff[1] = write_data;
spi_send(&ee_25xx_spi_dev,send_buff,2);
}
//
uint8_t ee_25xx_read_status(void)
{
uint8_t read_status = 0,send_buff[1];
send_buff[0] = REG_READ_STATUS;
spi_send_then_recv(&ee_25xx_spi_dev,send_buff,1,&read_status,1);
return read_status;
}
//
static uint8_t ee_25xx_wait_busy(void)
{
uint32_t i;
i = 0xFFFFF;
while (i--);
return 0;
}
//test
void ee_25xx_test(void)
{
uint8_t write_buff[255] = {0},read_buff[255] = {0},i;
for(i = 0;i < 0xff;i++)
write_buff = i;
ee_25xx_read_bytes(255,read_buff,255);
ee_25xx_write_bytes(255,write_buff,255);
memset(read_buff,0,255);
ee_25xx_read_bytes(255,read_buff,255);
for(i = 0;i < 0xff;i++)
write_buff = 255-i;
i=ee_25xx_read_status();
ee_25xx_write_bytes(255,write_buff,255);
ee_25xx_read_bytes(255,read_buff,255);
} |