打印
[Cortex-M0技术交流]

【第四批】sh007笔记【第一帖】-SPI通过PDMA对Flash进行读写

[复制链接]
3583|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sh007|  楼主 | 2011-11-17 08:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sh007 于 2011-11-17 13:07 编辑

拿到板子 本来想尽快学习使用,但是工作实在忙得没能按计划进行。最近也用到SPI FLASH,所以就先忽悠这个吧。
     板子上的串口 看来挺多人跟我一样 打印不了的。我用的是USBTOCOM的线,看资料调了一下串口,居然没反应,再我插拔串口线时,数据出来了,很奇怪,看了原理图后发现,串口的三个控制端也都引出,而且DTR还接了复位信号控制。但拔出来后DTR脚接触不好时,通讯就正常了。所以就先把R5,R6先焊掉,以后再研究串口控制。先不说上代码先。

SPI_PDMA_W25Q16BV.C主控函数文件
       设置主频50MHz,SPI 12MHz,然后对SPI FLASH 擦除,写和读进行操作
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2011 Nuvoton Technology Corp. All rights reserved. */
/*---------------------------------------------------------------------------------------------------------*/

#include <stdio.h>
#include "NUC1xx.h"
#include "DrvUART.h"
#include "DrvSYS.h"
#include "DrvSPI.h"
#include "DrvPDMA.h"
#include "SPI_FLASH_PDMA.h"
#include "Driver\DrvGPIO.h"

#define RW_LEN 80

uint8_t SPI_PDMA_RXBuf[RW_LEN];
uint8_t SPI_PDMA_TXBuf[RW_LEN];

void RCC_Config(void);
void UART_Config(void);

int main()
{
uint16_t writenum,readnum;

RCC_Config();
UART_Config();
SPI_Init();
PDMA_Init(RW_LEN);


printf("\n");
printf("+----------------------------------------------------------------------+\n");
printf("| NUC120助学板之SPI PDMA FLASH---W25Q16BV |\n");
printf("+----------------------------------------------------------------------+\n");
printf("***NUC120***配置主频为: %2d MHz.\n",DrvSYS_GetHCLKFreq()/1000000);
printf("---SPI1主机模式,频率为: %2d MHz.\n", DrvSPI_GetClock1Freq(eDRVSPI_PORT1)/1000000);

printf("开始擦除整片FLASH...\n");
SPIFlash_ChipErase();
SPIFlash_WaitReady();
printf("整片FLASH擦除完成。\n");
for(writenum=0;writenum<RW_LEN;writenum++)
{
SPI_PDMA_TXBuf[writenum]= writenum;
SPI_PDMA_RXBuf[writenum]= 0;
}
DrvSYS_Delay(500000);
printf("开始写入数据:\n");
// Trigger PDMA specified Channel
DrvPDMA_CHEnableTransfer(eDRVPDMA_CHANNEL_1);
SPIFlash_PDMA_PageProgram(0x0);

for(writenum=0;writenum<RW_LEN;writenum++)
{
if(writenum%16 == 0 ) printf("\n");
printf("0x%x,", SPI_PDMA_TXBuf[writenum]);
}

DrvSYS_Delay(500000);
printf("开始读出数据:\n");
// Trigger PDMA specified Channel
DrvPDMA_CHEnableTransfer(eDRVPDMA_CHANNEL_0);
SPIFlash_PDMA_Read(0x0);
for(readnum=0;readnum<RW_LEN;readnum++)
{
if(readnum%16 == 0 ) printf("\n");
printf("0x%x,", SPI_PDMA_RXBuf[readnum]);
}
while(1)
{}

}
void RCC_Config(void)
{
UNLOCKREG();
SYSCLK->WRCON.XTL12M_EN = 1;
// Waiting for 12M Xtal stalble
DrvSYS_Delay(5000);

//HCLK 为外部12M 通过PLL倍频到 50MHz.
DrvSYS_Open(50000000);
DrvSYS_Delay(5000);
LOCKREG();

}
void UART_Config()
{
STR_UART_T sParam;
// Set UART I/O
DrvGPIO_InitFunction(E_FUNC_UART0);

//Select UART Clock Source From 12MHz
DrvSYS_SelectIPClockSource(E_SYS_UART_CLKSRC, 0);

// UART Setting
sParam.u32BaudRate = 9600;
sParam.u8cDataBits = DRVUART_DATABITS_8;
sParam.u8cStopBits = DRVUART_STOPBITS_1;
sParam.u8cParity = DRVUART_PARITY_NONE;
sParam.u8cRxTriggerLevel= DRVUART_FIFO_1BYTES;

// Set UART Configuration
DrvUART_Open(UART_PORT0, &sParam);

}
SPI_FLASH_PDMA.c SPI 利用PDMA进行读写的操作函数。

#include <stdio.h>
#include "NUC1xx.h"
#include "DrvUART.h"
#include "DrvSYS.h"
#include "DrvSPI.h"
#include "DrvGPIO.h"
#include "DrvPDMA.h"
#include "SPI_FLASH_PDMA.h"

#define Enable_SPI1_W25Q16BV        (GPIOA->DOUT &= ~(1 << 14))
#define Disable_SPI1_W25Q16BV       (GPIOA->DOUT |= (1 << 14))


void PDMA0_Callback(void);
void PDMA1_Callback(void);

volatile uint32_t PDMA0_INT_Flag, PDMA1_INT_Flag;
STR_PDMA_T sPDMA;  
uint32_t  SPIPort;
uint32_t u32ByteCount, u32FlashAddress, u32PageNumber;

extern uint8_t SPI_PDMA_RXBuf[];
extern uint8_t SPI_PDMA_TXBuf[];

void SPI_Init(void)
{  
      
    //SPI1 GPIO Init
    DrvGPIO_InitFunction(E_FUNC_SPI1);
    //Initialize SPI
    // Configure SPI0 as a master, 32-bit transaction
    DrvSPI_Open(eDRVSPI_PORT1, eDRVSPI_MASTER, eDRVSPI_TYPE1, 32,FALSE);
    // MSB first
    DrvSPI_SetEndian(eDRVSPI_PORT1, eDRVSPI_MSB_FIRST);
    // Set the active level of slave select.
    DrvSPI_SetSlaveSelectActiveLevel(eDRVSPI_PORT1, eDRVSPI_ACTIVE_LOW_FALLING);
    // SPI clock rate 12MHz
    DrvSPI_SetClockFreq(eDRVSPI_PORT1,12000000, 0);

    //设置PA14为输出,PA14为W25Q16BV的位选
    DrvGPIO_Open(E_GPA, 14, E_IO_OUTPUT);
                                                     
}

void PDMA_Init(uint16_t RW_LEN)
{
    /* -------------------------------------------- */
    /* Configure PDMA Channel 0 to receive SPI1 Rx0 */
    /* -------------------------------------------- */
    // PDMA Init
    DrvPDMA_Init();
    // SPI Port = SPI1 Rx0
    SPIPort = SPI1_BASE + 0x10;
    // PDMA Setting
    DrvPDMA_SetCHForAPBDevice(eDRVPDMA_CHANNEL_0, eDRVPDMA_SPI1, eDRVPDMA_READ_APB);
    // CH0 RX Setting
    sPDMA.sSrcCtrl.u32Addr          = SPIPort; //源地址
    sPDMA.sDestCtrl.u32Addr         = (uint32_t)SPI_PDMA_RXBuf;//目标地址,这里是内部RAM的一块区域   
    sPDMA.u8TransWidth              = eDRVPDMA_WIDTH_8BITS;
    sPDMA.u8Mode                    = eDRVPDMA_MODE_APB2MEM;
    sPDMA.sSrcCtrl.eAddrDirection   = eDRVPDMA_DIRECTION_FIXED;
    sPDMA.sDestCtrl.eAddrDirection  = eDRVPDMA_DIRECTION_INCREMENTED;
    sPDMA.i32ByteCnt                = RW_LEN;  
    DrvPDMA_Open(eDRVPDMA_CHANNEL_0, &sPDMA);
    // Enable INT
    DrvPDMA_EnableInt(eDRVPDMA_CHANNEL_0, eDRVPDMA_BLKD);
    // Install Callback function   
    DrvPDMA_InstallCallBack(eDRVPDMA_CHANNEL_0, eDRVPDMA_BLKD, (PFN_DRVPDMA_CALLBACK) PDMA0_Callback );
   
    /* -------------------------------------------- */
    /* Configure PDMA Channel 1 to receive SPI1 Tx0 */
    /* -------------------------------------------- */
    // SPI Port = SPI1 Tx0
    SPIPort = SPI1_BASE + 0x20;
    // PDMA Setting
    DrvPDMA_SetCHForAPBDevice(eDRVPDMA_CHANNEL_1, eDRVPDMA_SPI1, eDRVPDMA_WRITE_APB);
    // CH0 TX Setting
    sPDMA.sSrcCtrl.u32Addr          = (uint32_t)SPI_PDMA_TXBuf;
    sPDMA.sDestCtrl.u32Addr         = SPIPort;   
    sPDMA.u8TransWidth              = eDRVPDMA_WIDTH_8BITS;
    sPDMA.u8Mode                    = eDRVPDMA_MODE_MEM2APB;
    sPDMA.sSrcCtrl.eAddrDirection   = eDRVPDMA_DIRECTION_INCREMENTED;
    sPDMA.sDestCtrl.eAddrDirection  = eDRVPDMA_DIRECTION_FIXED;
    sPDMA.i32ByteCnt                = RW_LEN;  
    DrvPDMA_Open(eDRVPDMA_CHANNEL_1, &sPDMA);
    // Enable INT
    DrvPDMA_EnableInt(eDRVPDMA_CHANNEL_1, eDRVPDMA_BLKD);
    // Install Callback function   
    DrvPDMA_InstallCallBack(eDRVPDMA_CHANNEL_1, eDRVPDMA_BLKD, (PFN_DRVPDMA_CALLBACK) PDMA1_Callback );
}

void SPIFlash_PDMA_PageProgram(uint32_t StartAddr)
{
    uint32_t au32SourceData;
   
    // configure transaction length as 8 bits
    DrvSPI_SetBitLength(eDRVSPI_PORT1, 8);

    //CS =0 使能W25Q16BV
    Enable_SPI1_W25Q16BV;
   
    // send Command: 0x06, Write enable
    au32SourceData = 0x06;
    DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);
   
    // wait
    while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {}
   
    //CS =1 禁止W25Q16BV
    Disable_SPI1_W25Q16BV;

    //CS =0 使能W25Q16BV
    Enable_SPI1_W25Q16BV;
   
    // send Command: 0x02, Page program
    au32SourceData = 0x02;
    DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);
   
    // wait
    while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {}
   
    // configure transaction length as 24 bits
    DrvSPI_SetBitLength(eDRVSPI_PORT1, 24);        
   
    // send 24-bit start address
    au32SourceData = StartAddr;
    DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);
            
    // wait
    while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {}
   
    // configure transaction length as 8 bits
    DrvSPI_SetBitLength(eDRVSPI_PORT1, 8);
   
    // enable SPI PDMA
    DrvSPI_SetPDMA(eDRVSPI_PORT1, eDRVSPI_TX_DMA, TRUE);

    // SPI go
    PDMA1_INT_Flag = 0;
    DrvSPI_SetGo(eDRVSPI_PORT1);
   
    // wait PDMA1 done
    while (1)
    {
        if (PDMA1_INT_Flag)
            {
            PDMA1_INT_Flag = 0;
            break;
            }
    }
            
    //CS =1 禁止W25Q16BV
    Disable_SPI1_W25Q16BV;  
}
void SPIFlash_PDMA_Read(uint32_t StartAddr)
{
    uint32_t au32SourceData;
   
    // configure transaction length as 8 bits
    DrvSPI_SetBitLength(eDRVSPI_PORT1, 8);        

    //CS =0 使能W25Q16BV
    Enable_SPI1_W25Q16BV;

    // send Command: 0x03, Read data
    au32SourceData = 0x03;
    DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);         

    // wait
    while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {}
   
    // configure transaction length as 24 bits
    DrvSPI_SetBitLength(eDRVSPI_PORT1, 24);        

    // send 24-bit start address
    au32SourceData = StartAddr;
    DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);         

    // wait
    while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {}
   
    // configure transaction length as 8 bits
    DrvSPI_SetBitLength(eDRVSPI_PORT1, 8);         

    // enable SPI PDMA
    DrvSPI_SetPDMA(eDRVSPI_PORT1, eDRVSPI_RX_DMA, TRUE);

    // SPI go
    PDMA0_INT_Flag = 0;
    DrvSPI_SetGo(eDRVSPI_PORT1);
   
    // wait PDMA0 done        
    while (1)
    {
        if (PDMA0_INT_Flag)
            {
            PDMA0_INT_Flag = 0;
            break;
            }
    }
    //CS =1 禁止W25Q16BV
    Disable_SPI1_W25Q16BV;
   
}


uint32_t SPIFlash_ReadStatusReg(void)
{
    uint32_t au32SourceData;
    uint32_t au32DestinationData;   

    // configure transaction length as 16 bits
    DrvSPI_SetBitLength(eDRVSPI_PORT1, 16);
            
     //CS =0 使能W25Q16BV
    Enable_SPI1_W25Q16BV;
   
    // send Command: 0x05, Read status register 1
    au32SourceData = 0x0500;
    DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);
   
    // wait
    while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {}
            
    //CS =1 禁止W25Q16BV
    Disable_SPI1_W25Q16BV;

    // dump Rx register
    DrvSPI_DumpRxRegister(eDRVSPI_PORT1, &au32DestinationData, 1);

    return (au32DestinationData & 0xFF);
}

void SPIFlash_WaitReady(void)
{
    uint32_t ReturnValue;
   
    do{
        ReturnValue = SPIFlash_ReadStatusReg();
        ReturnValue = ReturnValue & 1;
    }while(ReturnValue!=0); // check the BUSY bit
   
}
void SPIFlash_ChipErase(void)
{
   
    uint32_t au32SourceData;

    // configure transaction length as 8 bits
    DrvSPI_SetBitLength(eDRVSPI_PORT1, 8);         

     //CS =0 使能W25Q16BV
    Enable_SPI1_W25Q16BV;   

    // send Command: 0x06, Write enable
    au32SourceData = 0x06;
    DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);         

    // wait
    while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {}

    //CS =1 禁止W25Q16BV
    Disable_SPI1_W25Q16BV;

    //CS =0 使能W25Q16BV
    Enable_SPI1_W25Q16BV;   

    // send Command: 0xC7, Chip Erase
    au32SourceData = 0xc7;
    DrvSPI_SingleWrite(eDRVSPI_PORT1, &au32SourceData);         

    // wait
    while (DrvSPI_IsBusy(eDRVSPI_PORT1)) {}

    //CS =1 禁止W25Q16BV
    Disable_SPI1_W25Q16BV;
}   


/*---------------------------------------------------------------------------------------------------------*/
/* PDMA Callback function                                                                                  */
/*---------------------------------------------------------------------------------------------------------*/
void PDMA0_Callback(void)
{
    PDMA0_INT_Flag = 1;        

}

void PDMA1_Callback(void)
{
    PDMA1_INT_Flag = 1;        

}

相关帖子

沙发
sh007|  楼主 | 2011-11-17 09:00 | 只看该作者
忘记传工程文件了。

NUC120_SPI1_PDMA_W25Q16BV.rar

168.05 KB

使用特权

评论回复
板凳
plc_avr| | 2011-11-17 09:16 | 只看该作者
这个不错,顶!

使用特权

评论回复
地板
hotpower| | 2011-11-17 09:28 | 只看该作者
不错,spi加pdma是很不错的。m05x好像没有pdma

使用特权

评论回复
5
hotpower| | 2011-11-17 21:39 | 只看该作者
发放裤子,以便参加选美。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

174

帖子

1

粉丝