这是在前篇文章基础上修改的,实现DMA方式写数据到flash芯片W25Q64。
1.主函数:
#include <iocc2530.h>
#include "hal_types.h"
#include "hal_board.h"
#include "hal_mcu.h"
#include "string.h"
#include "W25Qxx.h"
#include "uart.h"
#include "bspDma.h"
#define LED P2_0
#define FLASH_SIZE 160 //FLASH 大小为8M字节
uint16 IDTYPE = 0;//W25QXX器件ID
uint8 string[] = "uart DMA test!";
//此数据是用来复制到内存的其他区域
uint8 data[] = "W25Q64 R&W test!";
//数据长度
#define DATA_AMOUNT sizeof(data)
//用来保存复制来的数据区域
uint8 copy[DATA_AMOUNT];
void InitClockTo32M(void)
{
CLKCONCMD &= ~0x40; //设置系统时钟源为 32MHZ晶振
while(!(CLKCONSTA & 0x40)); //等待晶振稳定
CLKCONCMD &= ~0x47; //设置系统主时钟频率为 32MHZ
}
void InitLed(void)
{
P2DIR |= 0x01;
P2_0 = 0;
}
void main(void)
{
InitClockTo32M();
InitLed();
W25QXX_Init();
IDTYPE = W25QXX_ReadID();//IDTYPE = 0xEF16
while(1)
{
//W25Q64读写测试,数据从data写入flash地址,等亮,从flash读取数据放到copy,可以通过电脑串口助手查看串口打印出来的数据
W25QXX_Write_Page(string,FLASH_SIZE,DATA_AMOUNT);//W25QXX_Read_Byte
LED = ~LED;
halMcuWaitMs(1000);
W25QXX_Read(copy,FLASH_SIZE,DATA_AMOUNT);//W25QXX_Read_Byte
LED = ~LED;
halMcuWaitMs(1000);
}
}
2.W25Q64.c
#define SPI_DMA
//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit或者32bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
void W25QXX_Write_Page(uint8* pBuffer,uint32 WriteAddr,uint16 NumByteToWrite)
{
W25QXX_Write_Enable(); //SET WEL
W25QXX_Enable(); //使能器件
SPI_ReadWriteByte(W25X_PageProgram);
#ifdef W25Q256 //如果是【W25Q256】地址为4字节
SPI_ReadWriteByte((uint8)((WriteAddr)>>24));//第4字节地址
#endif
SPI_ReadWriteByte((uint8)((WriteAddr)>>16));//发送24bit地址 ,//第3字节地址
SPI_ReadWriteByte((uint8)((WriteAddr)>>8)); //第2字节地址
SPI_ReadWriteByte((uint8)WriteAddr); //第1字节地址
#ifdef SPI_DMA
SPI_DMA_TX(pBuffer,NumByteToWrite);
#else
for(uint16 i=0;i<NumByteToWrite;i++)
{
SPI_ReadWriteByte(pBuffer[i]);
}
#endif
W25QXX_Wait_Busy(); //等待写入结束
W25QXX_Disable(); //取消片选
}
3.DMA配置
DMA_DESC __xdata dmaConfigTx;// DMA进入工作模式通道1
void NOPn(uint8 temp)
{
for(uint8 i=0;i<temp;i++)
{
NOP();
}
}
void DMA_Transmission(uint8 channel)
{
//DMA进入工作模式通道0
DMAARM |= (1<<channel);//为了任何DMA传输能够在该通道上发生,该位必须置1,对于非重复传输模式,一旦完成传送,该位自动清0
//一个通道准备工作(即获得配置数据)的时间需要9个系统时钟
NOPn(9);
DMAIRQ = 0; //清中断标志
//DMA通道0传送请求,即触发DMA传送
DMAREQ |= (1<<channel);//设置为1,激活DMA通道0(与一个触发事件具有相同的效果),当DMA传输开始清除该位
//等待DMA通道0传送完毕
//for (; !(DMAIRQ & DMAIRQ_DMAIF0););//当DMA通道0传送完成,DMAIRQ:DMAIF1位置1,与上DMAIRQ_DMAIF1(0x01),取非后为0退出循环
while(!(DMAIRQ&(1<<channel))); //等待DMA通道0传输结束
//清除中断标志
DMAIRQ = ~(1<<channel);
}
void SPI_DMA_TX(uint8 *tx_buf,uint16 NumByte)
{
//测试DMA通道,DMA_TRIG_UTX1触发,data数据复制到X_U1DBUF,测试成功,DMA传输无误
SET_WORD(dmaConfigTx.SRCADDRH, dmaConfigTx.SRCADDRL, tx_buf);//load address of the dma source
SET_WORD(dmaConfigTx.DESTADDRH, dmaConfigTx.DESTADDRL, &X_U1DBUF);//load address of the dma distanation
SET_WORD(dmaConfigTx.LENH, dmaConfigTx.LENL, NumByte); //LEN = nmax
dmaConfigTx.VLEN = DMA_VLEN_USE_LEN; // Transfer number of bytes commanded by n
dmaConfigTx.WORDSIZE = DMA_WORDSIZE_BYTE; // Each transfer is 8 bits
dmaConfigTx.TRIG = DMA_TRIG_UTX1;//DMA_TRIG_UTX1;DMA_TRIG_NONE
dmaConfigTx.TMODE = DMA_TMODE_SINGLE;// Transfer block of data (length len) after each DMA trigger//DMA_TMODE_SINGLE,DMA_TMODE_BLOCK
dmaConfigTx.SRCINC = DMA_SRCINC_1; // Increase source addr. by 1 between transfers
dmaConfigTx.DESTINC = DMA_DESTINC_0; // Keep the same dest. addr. for all transfers
dmaConfigTx.IRQMASK = DMA_IRQMASK_DISABLE;
dmaConfigTx.M8 = DMA_M8_USE_8_BITS; // Use all 8 bits of first byte in source data to determine the transfer count
dmaConfigTx.PRIORITY = DMA_PRI_HIGH; // DMA memory access has high priority
SET_WORD(DMA1CFGH, DMA1CFGL, &dmaConfigTx);
DMAARM = ABORT; //停止DMA所有通道进行传输
DMA_Transmission(1); //DMA进入工作模式通道1
}
4.仿真调试
5.待解决:
问题1:读出来到数组的数据第一个是0,从第二个开始才是写入的数据。
问题2:DMA配置接收,接收不到数据,启动DMA前,发送一个空字节,只能读出来第一个地址的数据。
下一步:研读flash芯片数据手册,看是否是flash芯片本身的问题,只能发一读一?