本帖最后由 Swallow_0322 于 2011-6-25 15:30 编辑
本工程主要包含三个任务:①普通类任务task_LOOK_SPI_PDMA_t:等待标志Flag_SPI低四位任意位置位 然后完成来自于uart0的任务;
②中断类任务LOOK_SPI_PDMA_t:通过PDMA中断完成SPI的读写操作;
③中断类任务uart0_t:uart 同步输出功能及接收功能
初始化设置: 时钟配置为 XTL12M_EN: 外部 4~24MHz 晶振使能
CPU时钟频率为12MHz
PB.0选择多功能输入RXD0 PB.1选择多功能输入TXD0
UART时钟选择外部12MHZ,并使能UART0时钟
SPI1时钟使能
SPI的端口设置:PC.8~11 依次为MCLK、SPICLK1、MISO10、MOSI10
PB.9 TM1
主要完成功能: UART0 接收到字符‘R’或‘r’实现读取W25Q16BV Page0 的内容;
UART0 接收到字符‘U’或‘u’实现W25Q16BV Page0 的内容加1;
UART0 接收到字符‘D’或‘d’实现W25Q16BV Page0 的内容减1;
UART0 接收到字符‘M’或‘m’实现读取W25Q16BV制造商ID及设备ID。
源文件:
main.h
#ifndef __LOOK_MAIN_H
#define __LOOK_MAIN_H
/*------------------------------------
LOOK头文件放入此处
------------------------------------*/
#include "look_config.h"
#include <look.h>
#include <instantiate>
/*------------------------------------
芯片及红杏头文件放入此处
------------------------------------*/
#include "NUC1xx.h"
#include "NUC1xxM051Seriescfg.h"
/*------------------------------------
系统定义的C++语言的头文件应该放入此处
------------------------------------*/
#include "LOOK_SPI_PDMA.h"
#include "SPI_PDMA.h"
#include "uart.h"
/*------------------------------------
全局类对象实例声明放入此位置
------------------------------------*/
#endif
SPI_PDMA.h#ifndef __LOOK_SPI_H
#define __LOOK_SPI_H
#define Enable_SPI_CS GPIOAs.DOUT.Bits.Pin14 = 0
#define DISABLE_SPI_CS GPIOAs.DOUT.Bits.Pin14 = 1
// LOOK_SPI_PDMA_t 类为应用层提供了 SPI 接口
class LOOK_SPI_PDMA_t : public interrupt_t {
public:
LOOK_SPI_PDMA_t() __OPT_ATTR__; //构造函数
sem_t sem_pdma0; // 信号灯为PDMA0传输结束
sem_t sem_pdma1; // 信号灯为PDMA1传输结束
protected:
bool isr(int vector); //中断服务例程
void dsr(int vector, uintptr_t count); //中断滞后服务例程
private://私有方法
inline void SPI1_SingleWrite(uint32_t *pu32Data); //Write data to SPI bus and trigger SPI to start transfer.
public://公有方法及属性
uint32_t SPI_ReadMidDid(void);
uint32_t SPI_ReadStatusReg1(void);
void SPI_WaitReady(void);
void SPI_ChipErase(void);
void SPI_SectorErase(uint32_t StartAddress);
void SPI_ReadData(uint32_t StartAddress);
void SPI_PageProgram(uint32_t StartAddress);
public://私有属性
volatile uint8_t SrcArray[256], DestArray[256];//数据缓冲区
};
extern LOOK_SPI_PDMA_t SPI_PDMA;
#endif
SPI_PDMA.CPP(对该文件内PDMA初始化部分内容的改进参见#9楼 HOT大叔指导并使用红杏头文件V1.20)
#include "main.h"
__OPT_INLINE__ LOOK_SPI_PDMA_t:OOK_SPI_PDMA_t():sem_pdma0(0),sem_pdma1(0) //构造函数
{
for (uint32_t i = 0; i < sizeof(SrcArray); i ++)
{ //清空缓存
SrcArray = 0;
DestArray = 0;
}
//SYSCLKs.APBCLK.Bits.SPI1_EN = 1; //使用LOOK进行初始化配置
SYSs.IPRSTC2.Bits.SPI1_RST = 1; //SPI1模块复位
SYSs.IPRSTC2.Bits.SPI1_RST = 0; //SPI1模块正常工作
// SYSs.GPCMFP.Bits.SPI1_SS0_MCLK = 1; //使用LOOK进行初始化配置
// SYSs.GPCMFP.Bits.SPI1_CLK = 1; //使用LOOK进行初始化配置
// SYSs.GPCMFP.Bits.SPI1_MOSI0= 1; //使用LOOK进行初始化配置
// SYSs.GPCMFP.Bits.SPI1_MISO0 = 1; //使用LOOK进行初始化配置
// SYSs.GPBMFP.Bits.TM1_SS11 = 1; //使用LOOK进行初始化配置
// SYSs.ALTMFP.Bits.PB9_S11 = 1; //使用LOOK进行初始化配置
SPI1s.CNTRL.Bits.TX_BIT_LEN = 0; //该寄存器用于标示一次传输中,完成的传输长度 32bits
SPI1s.CNTRL.Bits.SLAVE = 0; //MCU作为主机模式
SPI1s.SSR.Bits.SSR = 0; //当ASS位被清除,对该寄存器任何一位写1,将会激活SPI_SS [1:0]线,写0线上为非活动状态。
SPI1s.SSR.Bits.AUTOSS = 0; //该位清位,从机是否发出信号,由设置或清除SSR[1:0]寄存器决定
//禁止自动片选功能
SPI1s.CNTRL.Bits.CLKP = 0; // SCLK 低电平闲置
SPI1s.CNTRL.Bits.TX_NEG = 1; //SDO 信号在SPICLK的下降沿发送
SPI1s.CNTRL.Bits.RX_NEG = 0; //SDI 信号在SPICLK上升沿接收
//配置SPI1为主模式 TYPE1波形 32位传输
SPI1s.CNTRL.Bits.LSB = 0; //配置传输比特的顺序:优先发送/接收MSB
SPI1s.DIVIDER.Bits.DIVIDER2 = 0xFFFF;
SPI1s.DIVIDER.Bits.DIVIDER = ((12000000/2/1000000 + 1) >>1) - 1;
//设置SPI的时钟频率为1MHz
GPIOAs.PMD.Bits.PMD14 = GPIO_PMD_OUTPUT; //SPI_FLAH_CS配置为输出
DISABLE_SPI_CS;
// Enable PDMA Clock
SYSs.REGLOCK.Regs = 0x59;
SYSs.REGLOCK.Regs = 0x16;
SYSs.REGLOCK.Regs = 0x88;
SYSCLKs.AHBCLK.Bits.PDMA_EN = 1;
SYSs.REGLOCK.Regs = 0x00;
/* -------------------------------------------- */
/* Configure PDMA Channel 0 to receive SPI1 Rx0 */
/* -------------------------------------------- */
PDMA_GCR->DSSR0.SPI1_RXSEL = 0;
//APB设备选择 PDMA 通道 SPI选择PDMA通道0 读操作
//PDMA 通道0时钟使能
PDMA_GCR->GCRCSR.CLK0_EN = 1 ;
PDMA0s.CSR.Bits.PDMACEN = 1; //PDMA通道使能
PDMA0s.SAR.Regs = SPI1_BASE + 0x10; //PDMA 发送源地址寄存器 SPI1 Rx0
PDMA0s.DAR.Regs = (uint32_t)DestArray; //PDMA 传输目的地址寄存器
PDMA0s.CSR.Bits.SAD_SEL = 0b10; //传输源地址固定(适用于单数据 传递到多目的地址)
PDMA0s.CSR.Bits.DAD_SEL = 0b00; //传输目的地址 持续增加
PDMA0s.CSR.Bits.APB_TWS = 0b01; // 一字节(8 bits)为单位传输 用于 PDMA 运作
PDMA0s.CSR.Bits.MODE_SEL= 0b01; //01 = IP到存储器模式 (APB-to-Memory).
PDMA0s.BCR.Regs = 256; //PDMA 传输计数寄存器
//配置PDMA通道0
PDMA0s.IER.Bits.BLKD_IE = 1;
//使能PDMA通道0中断 中断源为:eDRVPDMA_BLKD(PDMA Transfer Done 中断使能)
/* -------------------------------------------- */
/* Configure PDMA Channel 1 to receive SPI1 Tx0 */
/* -------------------------------------------- */
PDMA_GCR->DSSR0.SPI1_TXSEL = 1;
//APB设备选择PDMA通道 SPI选择PDMA通道1 写操作
PDMA_GCR->GCRCSR.CLK1_EN = 1 ;
PDMA1s.SAR.Regs = (uint32_t)SrcArray; //PDMA 发送源地址寄存器
PDMA1s.DAR.Regs = SPI1_BASE + 0x20; //PDMA 传输目的地址寄存器
PDMA1s.CSR.Bits.SAD_SEL = 0b00; //传输源地址 持续增加
PDMA1s.CSR.Bits.DAD_SEL = 0b10; //传输目的地址不变
PDMA1s.CSR.Bits.APB_TWS = 0b01; // 一字节(8 bits)为单位传输 用于 PDMA 运作
PDMA1s.CSR.Bits.MODE_SEL= 0b10; //存储器到 IP 模式 (Memory-to-APB)
PDMA1s.BCR.Regs = 256; //PDMA 传输计数寄存器
//配置PDMA通道1
PDMA1s.IER.Bits.BLKD_IE = 1;
//使能PDMA通道1中断 中断源为:eDRVPDMA_BLKD(PDMA Transfer Done 中断使能)
attach(PDMA_IRQn); //连接PDMA中断
vector_t::enable(PDMA_IRQn); //使能PDMA中断
}
// 中断服务例程
bool LOOK_SPI_PDMA_t::isr(int vector)
{
if (PDMA0s.ISR.Bits.BLKD_IF)
{
PDMA0s.ISR.Bits.BLKD_IF = 1;
sem_pdma0.do_post(); //释放一个信号量资源
}
if (PDMA1s.ISR.Bits.BLKD_IF)
{
PDMA1s.ISR.Bits.BLKD_IF = 1;
sem_pdma1.do_post(); //释放一个信号量资源
}
return FALSE;
}
// 中断滞后服务例程
void LOOK_SPI_PDMA_t::dsr(int vector, uintptr_t count)
{
}
void LOOK_SPI_PDMA_t::SPI1_SingleWrite(uint32_t *pu32Data)
{
while (SPI1s.CNTRL.Bits.GO_BUSY);
SPI1s.TX0.Regs = *pu32Data;
SPI1s.CNTRL.Bits.GO_BUSY = 1;
}
void LOOK_SPI_PDMA_t::SPI_WaitReady(void)
{
uint32_t ReturnValue;
do{
ReturnValue = SPI_ReadStatusReg1();
ReturnValue = ReturnValue & 1;
}while(ReturnValue!=0);
//检查从设备状态寄存器1的BUSY位 等待其为0
}
/*****************************
** Name: SPI_ReadMidDid
** Function: W25Q16BV读制造商ID及设备ID函数
** Input: None
** OutPut: MID & DID
** Data: 2011-06-18
** Note:
****************************/
uint32_t LOOK_SPI_PDMA_t::SPI_ReadMidDid(void)
{
uint32_t au32SourceData;
uint32_t au32DestinationData;
SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
//配置SPI传输的比特长度:8 bits
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0x90;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x90 (Read Manufacturer/Device ID)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
//配置SPI传输的比特长度:24 bits
au32SourceData = 0x0;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x00 (24-bit Address)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
SPI1s.CNTRL.Bits.TX_BIT_LEN = 16;
//配置SPI传输的比特长度:16 bits
au32SourceData = 0x0;
SPI1_SingleWrite(&au32SourceData);
//接收数据
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
DISABLE_SPI_CS;
//从设备片选信号取消激活
au32DestinationData = SPI1s.RX0.Regs;
//从接收寄存器读数据. 但是不触发下一次数据传输.
return (au32DestinationData & 0xffff);
}
/*****************************
** Name: SPI_ReadStatusReg1
** Function: W25Q16BV读状态寄存器1函数
** Input: None
** OutPut: ReadStatusReg1
** Data: 2011-06-18
** Note:
****************************/
uint32_t LOOK_SPI_PDMA_t::SPI_ReadStatusReg1(void)
{
uint32_t au32SourceData;
uint32_t au32DestinationData;
SPI1s.CNTRL.Bits.TX_BIT_LEN = 16;
//配置SPI传输的比特长度:16 bits
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0x0500;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x0500 (Read status register 1)
while (SPI1s.CNTRL.Bits.GO_BUSY) ;
//等待SPI端口空闲
DISABLE_SPI_CS;
//从设备片选信号取消激活
au32DestinationData = SPI1s.RX0.Regs;
//从接收寄存器读数据. 但是不触发下一次数据传输.
return (au32DestinationData & 0xFF);
}
/*****************************
** Name: SPI_ChipErase
** Function: W25Q16BV片擦除函数
** Input: None
** OutPut: None
** Data: 2011-06-18
** Note:
****************************/
void LOOK_SPI_PDMA_t::SPI_ChipErase(void)
{
uint32_t au32SourceData;
SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
//配置SPI传输的比特长度:8 bits
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0x06;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x06 (Write enable)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
DISABLE_SPI_CS;
//从设备片选信号取消激活
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0xC7;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0xC7 (Chip Erase)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
DISABLE_SPI_CS;
//从设备片选信号取消激活
}
/*****************************
** Name: SPI_SectorErase
** Function: W25Q16BV扇区擦除函数
** Input: StartAddress
** OutPut: None
** Data: 2011-06-18
** Note:
****************************/
void LOOK_SPI_PDMA_t::SPI_SectorErase(uint32_t StartAddress)
{
uint32_t au32SourceData;
SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
//配置SPI传输的比特长度:8 bits
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0x06;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x06 (Write enable)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
DISABLE_SPI_CS;
//从设备片选信号取消激活
SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
//配置SPI传输的比特长度:8 bits
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0x20;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x20 (Sector Erase)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
//配置SPI传输的比特长度:24 bits
au32SourceData = StartAddress&0xFFF000;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: StartAddress
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
DISABLE_SPI_CS;
//从设备片选信号取消激活
}
/*****************************
** Name: SPI_ReadData
** Function: W25Q16BV读数据函数
** Input: StartAddress
** OutPut: None
** Data: 2011-06-18
** Note:
****************************/
void LOOK_SPI_PDMA_t::SPI_ReadData(uint32_t StartAddress)
{
uint32_t au32SourceData;
SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
//配置SPI传输的比特长度:8 bits
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0x03;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x03 (Read data)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
//配置SPI传输的比特长度:24 bits
au32SourceData = StartAddress;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: StartAddress
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
//配置SPI传输的比特长度:8 bits
SPI1s.DMA.Bits.RX_DMA_GO = 1;
//开始DMA接收模式,SPI模块自动切换为DMA模式接收
SPI1s.CNTRL.Bits.GO_BUSY = 1;
//设定GO_BUSY 比特来触发 SPI 数据传输.
while(!sem_pdma0.wait());
DISABLE_SPI_CS;
//从设备片选信号取消激活
}
/*****************************
** Name: SPI_PageProgram
** Function: W25Q16BV按页编程函数
** Input: StartAddress
** OutPut: None
** Data: 2011-06-18
** Note:
****************************/
void LOOK_SPI_PDMA_t::SPI_PageProgram(uint32_t StartAddress)
{
uint32_t au32SourceData;
SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
//配置SPI传输的比特长度:8 bits
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0x06;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x06 (Write enable)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
DISABLE_SPI_CS;
//从设备片选信号取消激活
Enable_SPI_CS;
//激活/配置从设备片选信号
au32SourceData = 0x02;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: 0x02 (Page program)
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
SPI1s.CNTRL.Bits.TX_BIT_LEN = 24;
//配置SPI传输的比特长度:24 bits
au32SourceData = StartAddress;
SPI1_SingleWrite(&au32SourceData);
//发送数据到 SPI 总线: StartAddress
while (SPI1s.CNTRL.Bits.GO_BUSY) {}
//等待SPI端口空闲
SPI1s.CNTRL.Bits.TX_BIT_LEN = 8;
//配置SPI传输的比特长度:8 bits
SPI1s.DMA.Bits.TX_DMA_GO = 1;
//使能SPI1且模式为DMA-Transmitting模式
SPI1s.CNTRL.Bits.GO_BUSY = 1;
//设定GO_BUSY 比特来触发 SPI 数据传输.
while(!sem_pdma1.wait());
DISABLE_SPI_CS;
//从设备片选信号取消激活
}
LOOK_SPI_PDMA_t SPI_PDMA;
//=========================END OF FILE=========================//
其它文件见工程包!
工程包:
LOOK_SPI_PDMA.rar
(771.58 KB)
|