AT91SAM7S64资料汇总,感兴趣的朋友请进
AT91SAM7S64带usb,貌似j-link上就是这个用的它 点击此处下载 ourdev_599610GZGJIL.pdf(文件大小:5.45M) (原文件名:AT91SAM7S64中文说明.pdf) 点击此处下载 ourdev_599633EUXVUK.pdf(文件大小:392K) (原文件名:AT91SAM7S64调试笔记 .pdf) 点击此处下载 ourdev_599641OMT5AE.rar(文件大小:2.48M) (原文件名:新建文件夹.rar) 几年前用AT91SAM7S64设计过好几个产品,挺好用的。 是的,比较老.今天处理废品把这些没用的书和旧板都卖给收废品的了
看到有些板子上有AT91SAM7S64就留了几个,外壳也挺漂亮的
http://cache.amobbs.com/bbs_upload782111/files_34/ourdev_599820LY32S4.jpg
(原文件名:zigbee.jpg) http://cache.amobbs.com/bbs_upload782111/files_34/ourdev_599821YRJZTF.jpg
(原文件名:zigbee.jpg) 这个模块的原理图: http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_604507CI61IY.jpg
(原文件名:64.jpg) USB-Zigbee Key软件设计说明
硬件总体包括三部分:主控芯片、FLASH和Zigbee模块,其中Zigbee模块由无线组负责,它和主控芯片之间的通信通过串口实现;主控芯片和FLASH之间通过SPI通信。其具体功能描述如下:
提供一个USB串行接口,用于连接PC;
提供ZigBee模块,相关需求请参见 “ZigBee模块需求”;
一个指示密钥获取状态的指示灯(例如在获取密钥的过程中指示灯闪,获取完毕后灯灭)。 1. 任务概述
1.1. 目标
1、 通过USB口和上位PC机通信
2、 通过USART口和zbm模块通信
3、 通过SPI口和FLASH通信
1.2. 运行环境
1、 软件环境为IAR Embedded workbench for ARM V4.31.A
2、 硬件环境为AT91SAM7S64
1.3. 需求概述
整个系统的需求可以概括为以下两个方面:
1、 建立上位PC机和数据存储FLASH之间的数据连接
2、 建立上位PC机和zbm无线模块之间的数据连接 http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_604510K1HXOT.jpg
(原文件名:tu.jpg) 2.2. 总体结构和模块外部设计
程序总体为顺序结构,只有接收zbm数据采用中断插入方式。模块之间通过数据缓存区来交换信息。
需要注意的是,因为ARM7具有DMA方式,所以实际数据传输流程是不需要MCU一直进行干预的。 2.3. 功能分配
根据功能,整个系统可以分为一下模块:USB读写模块,USB命令处理模块,SPI读写模块,USART读写模块 3. 各个模块总体规划说明
3.1. USB读写模块
USB读写模块拥有最高优先级,它是整个系统的核心。它通过USB的不同端点来接收或者发送数据。
3.2. USB命令处理模块
根据USB-Key协议,解析收到的命令,再调用相应的数据处理模块进行处理;完成相应的动作之后,将处理结果进行封包,通过USB读写模块传回PC机。
3.3. SPI读写模块
当需要对外置FLASH存储器进行操作时,调用SPI读写模块进行数据传递。数据传递的方向、大小和地址都由上位PC机通过USB-Key协议来确定。
3.4. USART读写模块
USART读写模块在系统中拥有次高的优先级,仅次于USB读写模块。之所以选用这种优先级排序,主要是考虑到USB命令的读写是系统稳定工作的保证,而且zbm模块的通信速率和通信量相对较小。
USART的读操作采用了ping-pong模式,这样可以保证,在USB读取模块操作共享数据区的过程中,USART模块能正确的接收数据。 4. 接口设计
4.1. 外部接口
USB接口:USB控制端点进行枚举处理、USB数据端点读写数据
USART:DMA中断方式读写数据
SPI:DMA中断方式读写数据
4.2. 内部接口
Ping-pong模式共享数据缓存区。 5. 系统可靠性设计规划
5.1. 运行设计
各个模块自身采用DMA方式收发数据。
除USART读数据外,其余模块只能通过主程序直接调用启动。
Ping-pong模式共享数据缓存,保证数据安全和完整。
5.2. 出错处理设计
5.2.1. 出错处理对策
只能由PC上位机通过USB控制端点零来进行重启。
5.3. 可测试性设计
根据协议,只要数据处理完成,则通过USB数据入端点返回处理结果。 http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_604515KKEK22.jpg
(原文件名:usart.jpg)
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_604516HYY4DB.jpg
(原文件名:usb_ctrl.jpg)
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_604517OZ4FXS.jpg
(原文件名:usb_in.jpg)
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_604518IWP4AD.jpg
(原文件名:程序流程.jpg) /* C **************************************************************************/
// 名称:main.c
// 功能:
// 说明:
/* C **************************************************************************/
/* include */
#include "compiler.h"
#include "board.h"
#include "basic.h"
#if check_flash
#include "usb_spi.h"
#endif
struct _zkey_usb_ms s_MASS;
char usb_running;
uint GV_usart_rec_length; // usart收到的数据总长
#if usbziji_v1
uint zkeyF_isusbconnect()
{
return (true);
}
#endif
extern void zkeyF_USART_Open( void );
void main ( void )
{
AT91C_BASE_RSTC->RSTC_RMR = AT91C_RSTC_URSTEN | (0x4<<8) | (unsigned int)(0xA5<<24); // 允许复位,最小复位时间960 us
zkeyF_led_init();
usb_running = 0;
GV_usart_rec_length = 0;
zkeyF_spi_start();
zkeyF_usb_open();
while(!s_MASS.isconfigured(&s_MASS));
zkeyF_USART_Open();
while(1)
{
zkeyF_usb_task(&s_MASS);
if(usb_running == 1) // from 0-> 1
{
AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED_MASK ) ; // 点亮LED
}
else
{
AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_MASK ); // 关闭LED
}
} #include "basic.h"
/*--------------------- global variable --------------------------------------*/
extern struct _s_usb_cbw ms_usb_cbw;
extern struct _s_usb_csw ms_usb_csw;
void zkeyF_led_init (void)
{
AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, LED_MASK ) ; // PIOA配置为输出,用于LED
AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_MASK ) ; // 熄灭LED
} //*----------------------------------------------------------------------------
//* File Name : dataflash.c
//* Object : SPI dataflash 程序
//* Creation :
//*----------------------------------------------------------------------------
// Include Standard files
#include "usb_spi.h"
#if new_board
uchar FLASH_PBR;
#include "down_pbr.h"
#endif
#define SpiDataflash_SYS_LEVEL 6//定义SpiDataflash的中断优先级为最高优先级
zkeyS_dataflashfeatures deviceAT45DB161d; //定义一个数据结构为 AT45DB321C
zkeyS_dataflashdesc dataflashdesc; //定义一个数据结构为 dataflashdesc
zkeyS_dataflash dataflash; //定义一个数据结构为 dataflash
// ucharBuffer_Dataflash; //定义一个缓冲区为 dataflash
//*-----------------------定义需要的,而库里没有的函数---------------------------
__inline unsigned int AT91F_SPI_GetStatus( // \return SPI Interrupt Mask Status
AT91PS_SPI pSpi) // \argpointer to a SPI controller
{
return pSpi->SPI_SR;
}
//*----------------------------------------------------------------------------
//* 函数名: AT91F_SPI0_CfgSPI
//* 功能:配置SPI0
//*----------------------------------------------------------------------------
static voidzkeyF_spi_cfgspi(void)
{
//* 复位SPI
AT91F_SPI_Reset(AT91C_BASE_SPI);
//* 配置 SPI 工作在主模式--固定外设--NPCS0片选 //如果选用不同的片选可在此处修改
AT91F_SPI_CfgMode(AT91C_BASE_SPI, AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED | AT91C_SPI_MODFDIS | (0xE<<16));
//* SPI MODE 0:CPOL/NCPHA 0/1, 传输后片选上升, 配置8 位数据位
AT91F_SPI_CfgCs(AT91C_BASE_SPI,0, AT91C_SPI_NCPHA | AT91C_SPI_BITS_8 | (AT91C_SPI_DLYBS & 0x100000) |((MCK/(DATAFLASH_CLK)) << 8));
//* 启动 SPI0
AT91F_SPI_Enable(AT91C_BASE_SPI);
}
//*----------------------------------------------------------------------------
//* 函数名:zkeyF_cfgdataflash
//* 功能: 初始化DataFlash 数据结构
//*----------------------------------------------------------------------------
static void zkeyF_cfgdataflash (void)
{
// 初始化DATAFLASH特性,使之适合AT45D321C //如果选用其他型号的的FLASH则依据FLASH的特性,在此修改
deviceAT45DB161d.pages_number = 4095;
deviceAT45DB161d.pages_size = 512;
deviceAT45DB161d.page_offset= 10;
deviceAT45DB161d.byte_mask = 0x300;
// 初始化 AT91S_DataflashDesc 结构
dataflashdesc.state = IDLE;
dataflashdesc.DataFlash_state = IDLE;
// 初始化 AT91S_DataFlash 全局结构, AT45DB321C 作为默认选择
dataflash.pDataFlashDesc = &dataflashdesc;
dataflash.pDevice = &deviceAT45DB161d;
}
//*----------------------------------------------------------------------------
//* 函数名:zkeyF_dataflashhandler
//* 功能: SPI0中断处理程序
//*----------------------------------------------------------------------------
static void zkeyF_dataflashhandler(
zkeyPS_dataflashdesc pDesc,
unsigned int status)
{
//* 判断是否接收完,产生的中断
if (( status & AT91C_SPI_RXBUFF))
{
if( pDesc->state == BUSY)
{
//*设置DATAFLASH的下一个状态为空闲状态,
pDesc->state = IDLE;
if (pDesc->DataFlash_state == DATAFLASH_GET_STATUS)
pDesc->DataFlash_state = *( (unsigned char *) (pDesc->rx_cmd_pt) +1);
//AT91F_USRT_Printk(AT91C_BASE_US0,"receive interrupt\n\r");
//* 禁止传输中断
AT91C_BASE_SPI->SPI_IDR = AT91C_SPI_RXBUFF;
//*允许PDC 发送和接收 --PDC 传输控制寄存其
AT91C_BASE_SPI->SPI_PTCR = AT91C_PDC_TXTDIS + AT91C_PDC_RXTDIS;
return;
}
}
//否则状态错误
pDesc->state = ERROR;
// 禁止PDC接收和发送中断
AT91C_BASE_SPI->SPI_PTCR = AT91C_PDC_TXTDIS + AT91C_PDC_RXTDIS;
//禁止出RXBUFF之外的所有中断
AT91C_BASE_SPI->SPI_IDR = status;
}
//*----------------------------------------------------------------------------
//* 函数名: zkeyF_spi_handler
//* 功能: SPI中断入口
//*----------------------------------------------------------------------------
void zkeyF_spi_handler(void)
{
unsigned int status;
//禁止 SPI0 中断
AT91F_AIC_DisableIt(AT91C_BASE_AIC,AT91C_ID_SPI);
//--------------------------------------------------------------------------
//取得 SPI_SR 和 SPI_IMR ----的状态
status=( AT91F_SPI_GetStatus(AT91C_BASE_SPI)&AT91F_SPI_GetInterruptMaskStatus(AT91C_BASE_SPI));
//调用中断处理函数
zkeyF_dataflashhandler(dataflash.pDataFlashDesc, status);
//---------------------------------------------------------------------
// 允许SPI1中断
AT91F_AIC_EnableIt(AT91C_BASE_AIC,AT91C_ID_SPI);
}
//*----------------------------------------------------------------------------
//*函数名:zkeyF_spi_open
//* 功能: 初始化SPI0,与串口DataFlash通信
//*----------------------------------------------------------------------------
void zkeyF_spi_open(void)
{
// ============================= 初始化 SPI 接口 =============================
// 初始化 SPI 作为 dataflash 接口
zkeyF_spi_CfgPIO();
//开启SPI PMC
AT91F_SPI_CfgPMC();
//允许接收缓冲区满中断---RXBUFF
AT91F_SPI_EnableIt(AT91C_BASE_SPI,0x1<<6);
//配置SPI 特性
zkeyF_spi_cfgspi();
//开启 PDC
AT91F_PDC_Open(AT91C_BASE_PDC_SPI);
//配置 AT45DB161C
zkeyF_cfgdataflash();
// 配置 SPI 中断
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC,
AT91C_ID_SPI,
SpiDataflash_SYS_LEVEL,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
zkeyF_spi_handler);
// 允许 SPI0 中断
AT91F_AIC_EnableIt(AT91C_BASE_AIC,AT91C_ID_SPI);
}
//*----------------------------------------------------------------------------
//* 函数名:zkeyF_spiwrite
//* 功能:设置 PDC 传输功能
//说明:此处为重先编写的直接PDC传输功能,因为SPI接受和发送是同时的,所以直接对寄存器操作比较方便,
// 也可以调用库函数AT91F_SPI_ReceiveFrame()其功能与此处相同,
// 可参考usart.c 文件,里面的传输采用调用库函数来实现的!
// 详细了解,参见DATASHEET 的PDC部分。
//*----------------------------------------------------------------------------
static void zkeyF_spiwrite ( zkeyPS_dataflashdesc pDesc )
{
//设置设备的状态为忙,等待中断清除这种状态
pDesc->state = BUSY;
// 禁止PDC接收和发送中断
AT91C_BASE_SPI->SPI_PTCR = AT91C_PDC_TXTDIS + AT91C_PDC_RXTDIS;
//* 初始化发送和接收指针
AT91C_BASE_SPI->SPI_RPR = (unsigned int)pDesc->rx_cmd_pt ;
AT91C_BASE_SPI->SPI_TPR = (unsigned int)pDesc->tx_cmd_pt ;
//* 初始化发送和接收计数器
AT91C_BASE_SPI->SPI_RCR = pDesc->rx_cmd_size ;
AT91C_BASE_SPI->SPI_TCR = pDesc->tx_cmd_size ;
if ( pDesc->tx_data_size != 0 )
{
//* 初始化下一个接受和发送指针
AT91C_BASE_SPI->SPI_RNPR = (unsigned int)pDesc->rx_data_pt ;
AT91C_BASE_SPI->SPI_TNPR = (unsigned int)pDesc->tx_data_pt ;
//* 初始化下一个发送和接收计数器
AT91C_BASE_SPI->SPI_RNCR = pDesc->rx_data_size ;
AT91C_BASE_SPI->SPI_TNCR = pDesc->tx_data_size ;
}
//* 允许接收满中断---- RXBUFF
AT91C_BASE_SPI->SPI_IER = AT91C_SPI_RXBUFF;
//* PDC传输控制----- 允许PDC传输和接收
AT91C_BASE_SPI->SPI_PTCR = AT91C_PDC_TXTEN + AT91C_PDC_RXTEN;
}
//*----------------------------------------------------------------------------
//* 函数名:zkeyF_dataflashgetstatus
//* 功能: 读DATAFLASH的状态
//*----------------------------------------------------------------------------
static zkeyS_dataflashstatus zkeyF_dataflashgetstatus(zkeyPS_dataflashdesc pDesc)
{
//* 如果数据传输没有结束 ==> 返回 0
if( (pDesc->state) != IDLE)
return DATAFLASH_BUSY;
//* 首先发送和读取状态命令(D7H)
pDesc->command = DB_READ_STATUS;
pDesc->command = 0;
pDesc->DataFlash_state= DATAFLASH_GET_STATUS;
pDesc->tx_data_size = 0 ; //* 传输命令,接收读取的状态----非数据传输
pDesc->tx_cmd_pt = pDesc->command ;
pDesc->rx_cmd_pt = pDesc->command ;
pDesc->rx_cmd_size = 2 ;
pDesc->tx_cmd_size = 2 ;
zkeyF_spiwrite (pDesc);
return DATAFLASH_OK;
}
//*----------------------------------------------------------------------------
//* 函数名:zkeyF_dataflashsendcommand
//* 功能: 通过SPI发送命令到 dataflash
//*----------------------------------------------------------------------------
static zkeyS_dataflashstatus zkeyF_dataflashsendcommand (
zkeyPS_dataflash pDataFlash,
unsigned char OpCode,
unsigned int CmdSize,
unsigned int DataflashPageAddress)
{
unsigned int addr;
if ( (pDataFlash->pDataFlashDesc->state) != IDLE)
return DATAFLASH_BUSY;
//* process the address to obtain page address and byte address
addr = DataflashPageAddress << (pDataFlash->pDevice->page_offset);
//* fill thecommandbuffer */
pDataFlash->pDataFlashDesc->command = OpCode;
pDataFlash->pDataFlashDesc->command = (unsigned char)((addr & 0x00FF0000) >> 16);
pDataFlash->pDataFlashDesc->command = (unsigned char)((addr & 0x0000FF00) >>8);
pDataFlash->pDataFlashDesc->command = (unsigned char)((addr & 0x000000FF) >>0);
pDataFlash->pDataFlashDesc->command = 0;
pDataFlash->pDataFlashDesc->command = 0;
pDataFlash->pDataFlashDesc->command = 0;
pDataFlash->pDataFlashDesc->command = 0;
/* Initialize the SpiData structure for the spi write fuction */
pDataFlash->pDataFlashDesc->tx_cmd_pt =pDataFlash->pDataFlashDesc->command ;
pDataFlash->pDataFlashDesc->tx_cmd_size =CmdSize ;
pDataFlash->pDataFlashDesc->rx_cmd_pt =pDataFlash->pDataFlashDesc->command ;
pDataFlash->pDataFlashDesc->rx_cmd_size =CmdSize ;
/* send the command and read the data */
zkeyF_spiwrite (pDataFlash->pDataFlashDesc);
return DATAFLASH_OK;
}
//*----------------------------------------------------------------------------
//* 函数名: zkeyF_dataflashpageread
//* 功能:读取DATAFLASH的某一页
//*----------------------------------------------------------------------------
zkeyS_dataflashstatus zkeyF_dataflashpageread (
zkeyPS_dataflash pDataFlash,
unsigned int addr,
char *dataBuffer,
int sizeToRead )
{
pDataFlash->pDataFlashDesc->rx_data_pt = dataBuffer ; //* 读操作缓冲区的地址
pDataFlash->pDataFlashDesc->rx_data_size = sizeToRead; //* 读数据大小
pDataFlash->pDataFlashDesc->tx_data_pt = dataBuffer ;
pDataFlash->pDataFlashDesc->tx_data_size = sizeToRead;
//* 发送读命令到dataflash
return (zkeyF_dataflashsendcommand (pDataFlash, DB_MAIN_PAGE_READ, 8, addr));
}
//*----------------------------------------------------------------------------
//* 函数名:zkeyF_dataflashpagepgmbuf
//* 功能:通过缓冲区1向DATAFLASH写一页数据with erase
//*----------------------------------------------------------------------------
zkeyS_dataflashstatus zkeyF_dataflashpagepgmbuf(
zkeyPS_dataflash pDataFlash,
char *src,
unsigned int addr,
unsigned int SizeToWrite)
{
pDataFlash->pDataFlashDesc->tx_data_pt = src ;
pDataFlash->pDataFlashDesc->tx_data_size = SizeToWrite ;
pDataFlash->pDataFlashDesc->rx_data_pt = src;
pDataFlash->pDataFlashDesc->rx_data_size = SizeToWrite;
/* 发送写命令到dataflash */
return(zkeyF_dataflashsendcommand (pDataFlash,DB_MAIN_PROGRAM_BUFF1, 4, addr));
}
//*----------------------------------------------------------------------------
//* 函数名:zkeyF_dataflashpageerase
//* 功能: 通过缓冲区1或缓冲区2擦除DATAFLASH
//*----------------------------------------------------------------------------
zkeyS_dataflashstatus zkeyF_dataflashpageerase(
zkeyPS_dataflash pDataFlash,
char *src,
unsigned int address,
unsigned int SizeToWrite)
{
pDataFlash->pDataFlashDesc->tx_data_pt = src ;
pDataFlash->pDataFlashDesc->tx_data_size = SizeToWrite ;
pDataFlash->pDataFlashDesc->rx_data_pt = src;
pDataFlash->pDataFlashDesc->rx_data_size = SizeToWrite;
/* 发送擦除命令到dataflash */
return(zkeyF_dataflashsendcommand (pDataFlash, DB_PAGE_ERASE, 4, address));
}
//*----------------------------------------------------------------------------
//* 函数名:zkeyF_dataflashwaitready
//* 功能:等待DATAFLAH操作完 (bit7 of the status register == 1)
//*----------------------------------------------------------------------------
zkeyS_dataflashstatus zkeyF_dataflashwaitready(zkeyPS_dataflashdesc pDataFlashDesc, unsigned int timeout)
{
unsigned int i;
pDataFlashDesc->DataFlash_state = IDLE;
do
{
zkeyF_dataflashgetstatus(pDataFlashDesc);
timeout--;
// 简单的等待
for(i=0;i<1000;i++);
}
while( ((pDataFlashDesc->DataFlash_state & 0x80) != 0x80) && (timeout>0) );
if((pDataFlashDesc->DataFlash_state & 0x80) != 0x80)
return DATAFLASH_ERROR;
return DATAFLASH_OK;
}
void zkeyF_spi_select_flash ( AT91PS_SPI pSPI )
{
#if usbziji_v1
uint i;
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, FLASH_POWER_CONTROL);
for(i=0; i<100; i++);
#endif
pSPI->SPI_MR |= 0xe<<16;// 激活片选信号
}
void zkeyF_spi_CfgPIO (void)
{
AT91F_PIO_CfgPeriph(
AT91C_BASE_PIOA, // PIO controller base address
((unsigned int) AT91C_PA13_MOSI ) |
((unsigned int) AT91C_PA14_SPCK ) |
((unsigned int) AT91C_PA11_NPCS0 ) |
((unsigned int) AT91C_PA12_MISO ),
0);
}
// IN usb_bulk.h
// in basic.h
void zkeyF_spi_close(void)
{
;
}
void zkeyF_spi_start(void)
{
zkeyF_spi_open();
}
uchar zkeyF_scsi_get_flash_status ( void )
{
uint i;
uchar flash_status;
ushort time;
time = 50000;
while(time && zkeyF_dataflashgetstatus(dataflash.pDataFlashDesc)!=DATAFLASH_OK);
for(i=0;i<100;i++);
flash_status = dataflashdesc.DataFlash_state;
if (flash_status & 0x80)
flash_status = FLASH_OK;
else if (flash_status & 0x20)
flash_status = FLASH_PROTECT;
else if (flash_status == 0x00)
flash_status = FLASH_NO_PRESENT;
else
flash_status = FLASH_BUSY;
return(flash_status);
}
zkeyS_dataflashstatus zkeyF_dataflashconfigure ( zkeyPS_dataflash pDataFlash )
{
if ( (pDataFlash->pDataFlashDesc->state) != IDLE)
return DATAFLASH_BUSY;
//* fill thecommandbuffer */
pDataFlash->pDataFlashDesc->command = 0x3D;
pDataFlash->pDataFlashDesc->command = 0x2A;
pDataFlash->pDataFlashDesc->command = 0x80;
pDataFlash->pDataFlashDesc->command = 0xA6;
pDataFlash->pDataFlashDesc->command = 0;
pDataFlash->pDataFlashDesc->command = 0;
pDataFlash->pDataFlashDesc->command = 0;
pDataFlash->pDataFlashDesc->command = 0;
/* Initialize the SpiData structure for the spi write fuction */
pDataFlash->pDataFlashDesc->tx_cmd_pt =pDataFlash->pDataFlashDesc->command ;
pDataFlash->pDataFlashDesc->tx_cmd_size =4 ;
pDataFlash->pDataFlashDesc->rx_cmd_pt =pDataFlash->pDataFlashDesc->command ;
pDataFlash->pDataFlashDesc->rx_cmd_size =4 ;
/* send the command and read the data */
zkeyF_spiwrite (pDataFlash->pDataFlashDesc);
return DATAFLASH_OK; 先顶一个再看 /* C **************************************************************************/
// 名称: usb_enum.c
// 功能: usb功能的初始化、枚举处理过程等
// 说明:
/* C **************************************************************************/
#include "at91usb_conf.h"
typedef unsigned char uchar;
typedef unsigned intuint;
//应用于全局的变量控制、程序控制结构体
struct _KEYS_USBpskeyUSB;
void KEYF_USB_Open ( void );
KEYPS_USB KEYF_CDC_Open ( KEYPS_USB psUSB, AT91PS_UDP psUDP );
void KEYF_Init_USB ( KEYPS_USB psUSB );
static ucharKEYF_IsUSBConfigured ( KEYS_USB *psUSB );
static void KEYF_USB_Enumerate ( KEYS_USB *psUSB );
static void KEYF_USB_SendData ( AT91PS_UDP psUDP, const char *pData, uint length);
void KEYF_USB_SendZlp ( AT91PS_UDP psUDP );
void KEYF_USB_SendStall ( AT91PS_UDP psUDP );
static uint KEYF_USB_Write ( KEYS_USB *psUSB, const char *pData, uint Length );
static uint KEYF_USB_Read ( KEYS_USB *psUSB, char *pData, uint Length );
//void KEYF_Toggle_LED ( char LED );
KEYS_CDC_LINE_CODING line =
{
115200, // 波特率
0, // 1位停止位
0, // 无校验
8 // 8位数据
};
/* Fuction ********************************************************************/
//名称:KEYF_USB_Open
//功能:USB环境初始化 - PLL时钟、上拉电阻、初始化全局结构体等
//参数:无
//返回值:无
/* Fuction ********************************************************************/
void KEYF_USB_Open ( void )
{
// Set the PLL USB Divider
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ; // 设置PLL时钟
AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; // 允许48MHz USB时钟频率
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA,AT91C_PIO_PA21);// 设置PIO模式,配置为输出
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA,AT91C_PIO_PA21);// 设置上拉电阻
KEYF_CDC_Open(&pskeyUSB, AT91C_BASE_UDP); // 通过初始化usb结构体打开CDC
}
/* Fuction ********************************************************************/
//名称:AT91F_CDC_Open
//功能:初始化USB全局结构体 - pskeyUSB
//参数:全局结构体、当前USB寄存器地址
//返回值:全局结构体
/* Fuction ********************************************************************/
KEYPS_USB KEYF_CDC_Open ( KEYPS_USB pskeyUSB, AT91PS_UDP psUDP )
{
pskeyUSB->psUSB = psUDP; // USB寄存器地址
pskeyUSB->USBConfiguration= 0;
pskeyUSB->USBConnection = 0;
pskeyUSB->USBRcvBank = AT91C_UDP_RX_DATA_BK0;
pskeyUSB->IsUSBConfigured = KEYF_IsUSBConfigured;
pskeyUSB->USBWrite = KEYF_USB_Write;
pskeyUSB->USBRead = KEYF_USB_Read;
return pskeyUSB;
}
/* Fuction ********************************************************************/
//名称:KEYF_IsUSBConfigured
//功能:判断枚举处理状态
//参数:全局结构体
//返回值:当前配置序号
/* Fuction ********************************************************************/
static uchar KEYF_IsUSBConfigured ( KEYS_USB *pskeyUSB )
{
AT91PS_UDP psUDP = pskeyUSB->psUSB; // usb寄存器地址
AT91_REG usb_isr = psUDP->UDP_ISR;// isr寄存器状态
if ( usb_isr & AT91C_UDP_ENDBUSRES )// 总线重启
{
psUDP->UDP_ICR = AT91C_UDP_ENDBUSRES; // 清除总线重启标志-置ICR相应位
KEYF_Init_USB(pskeyUSB); // 初始化EP0
}
else if ( usb_isr & AT91C_UDP_EPINT0 )// 端点零发生中断
{
psUDP->UDP_ICR = AT91C_UDP_EPINT0;// 清除ep0中断标志
KEYF_USB_Enumerate ( pskeyUSB ); // 调用枚举处理函数
}
return pskeyUSB->USBConfiguration;// 返回当前配置序号
}
/* Fuction ********************************************************************/
//名称:KEYF_Init_USB
//功能:初始化EP0端点
//参数:当前使用的全局结构体
//返回值:无
/* Fuction ********************************************************************/
static void KEYF_Init_USB ( KEYPS_USB pskeyUSB )
{
AT91PS_UDP lcl_psUDP = pskeyUSB->psUSB; // usb寄存器地址
lcl_psUDP->UDP_RSTEP = (uint) -1; // 复位所有端点
lcl_psUDP->UDP_RSTEP = 0; // 清除EP0复位标志
lcl_psUDP->UDP_FADDR = AT91C_UDP_FEN; // 开USB功能允许
lcl_psUDP->UDP_CSR= ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ); // 使能端点,定义端点类型为控制
}
/* Fuction ********************************************************************/
//名称:KEYF_USB_Enumerate
//功能:处理主机枚举过程中调用
//参数:全局结构体
//返回值:无
/* Fuction ********************************************************************/
static void KEYF_USB_Enumerate( KEYPS_USB pskeyUSB )
{
AT91PS_UDP psUDP = pskeyUSB->psUSB; // USB寄存器
char bmRequestType, bRequest;
ushort wValue, wIndex, wLength, wStatus;
if ( !(psUDP->UDP_CSR & AT91C_UDP_RXSETUP))return; // FIFO中没有有效的设置数据包
bmRequestType =psUDP->UDP_FDR;
bRequest =psUDP->UDP_FDR;
wValue = (psUDP->UDP_FDR & 0xFF);
wValue |= (psUDP->UDP_FDR << 8);
wIndex = (psUDP->UDP_FDR & 0xFF);
wIndex |= (psUDP->UDP_FDR << 8);
wLength = (psUDP->UDP_FDR & 0xFF);
wLength |= (psUDP->UDP_FDR << 8);
if (bmRequestType & 0x80) // 传输方向设置
{
psUDP->UDP_CSR |= AT91C_UDP_DIR; // 设置端点传输方向为in - 对主机而言
while ( !( psUDP->UDP_CSR & AT91C_UDP_DIR ) ); // 等待设置完成
}
psUDP->UDP_CSR &= ~AT91C_UDP_RXSETUP;// 通知主机已经取走数据
while ( (psUDP->UDP_CSR& AT91C_UDP_RXSETUP) ); // 等待主机发送新的设置数据包
switch ( (bRequest << 8) | bmRequestType )
{
case STD_GET_DESCRIPTOR:
if ( wValue == 0x100 ) // 设备描述符
KEYF_USB_SendData( psUDP, DevDescriptor, Min(sizeof(DevDescriptor), wLength) );
else if ( wValue == 0x200 ) // 配置描述符
KEYF_USB_SendData( psUDP, User_CfgDescriptor, Min(sizeof(User_CfgDescriptor), wLength) );
else
KEYF_USB_SendStall( psUDP );
break;
case STD_SET_ADDRESS:
KEYF_USB_SendZlp ( psUDP );// 发送零长度数据
psUDP->UDP_FADDR = ( AT91C_UDP_FEN | wValue );// 使能端点 + 端点地址
psUDP->UDP_GLBSTATE = ( wValue ) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;// 配置USB器件状态
break;
case STD_SET_CONFIGURATION:
pskeyUSB->USBConfiguration = wValue;// 更改当前配置序号
KEYF_USB_SendZlp( psUDP );
psUDP->UDP_GLBSTATE = ( wValue ) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;// 配置成功与否
psUDP->UDP_CSR = ( wValue ) ? ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT ) : 0; // 配置端点1
psUDP->UDP_CSR = ( wValue ) ? ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN ): 0; // 配置端点2
psUDP->UDP_CSR = ( wValue ) ? ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_ISO_IN ) : 0; // 配置端点3
break;
case STD_GET_CONFIGURATION:
KEYF_USB_SendData( psUDP, (char*) &(pskeyUSB->USBConfiguration), sizeof(pskeyUSB->USBConfiguration) );
break;
case STD_GET_STATUS_ZERO:
wStatus = 0;
KEYF_USB_SendData(psUDP, (char*) &wStatus, sizeof(wStatus));
break;
case STD_GET_STATUS_INTERFACE:
wStatus = 0;
KEYF_USB_SendData(psUDP, (char*) &wStatus, sizeof(wStatus));
break;
case STD_GET_STATUS_ENDPOINT: // 获得端点状态
wStatus = 0;
wIndex &= 0x0F; // 请求的端点号
if ( (psUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <=3) ) // 端点必须已经被配置好
{
wStatus = (psUDP->UDP_CSR & AT91C_UDP_EPEDS) ? 0 : 1; // 端点使能的时候表示no halt
KEYF_USB_SendData(psUDP, (char*) &wStatus, sizeof(wStatus));
}
else if ( (psUDP->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == 0) ) // 端点0已经分配地址
{
wStatus = (psUDP->UDP_CSR & AT91C_UDP_EPEDS) ? 0 : 1;
KEYF_USB_SendData(psUDP, (char*) &wStatus, sizeof(wStatus));
}
else
KEYF_USB_SendStall(psUDP); // 端点已经停止
break;
case STD_SET_FEATURE_ZERO:
KEYF_USB_SendStall(psUDP);
break;
case STD_SET_FEATURE_INTERFACE:
KEYF_USB_SendZlp(psUDP);
break;
case STD_SET_FEATURE_ENDPOINT:
wIndex &= 0x0F;
if ( (wValue == 0) && wIndex && (wIndex <= 3))
{
psUDP->UDP_CSR = 0;
KEYF_USB_SendZlp(psUDP);
}
else
KEYF_USB_SendStall(psUDP);
break;
case STD_CLEAR_FEATURE_ZERO:
KEYF_USB_SendStall(psUDP);
break;
case STD_CLEAR_FEATURE_INTERFACE:
KEYF_USB_SendZlp(psUDP);
break;
case STD_CLEAR_FEATURE_ENDPOINT:
wIndex &= 0x0F;
if ( (wValue == 0) && wIndex && (wIndex <= 3))
{
if (wIndex == 1)
psUDP->UDP_CSR = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);
else if (wIndex == 2)
psUDP->UDP_CSR = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);
else if (wIndex == 3)
psUDP->UDP_CSR = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_ISO_IN);
KEYF_USB_SendZlp(psUDP);
}
else
KEYF_USB_SendStall(psUDP);
break;
// 处理CDC类请求
case SET_LINE_CODING:
while ( !(psUDP->UDP_CSR & AT91C_UDP_RX_DATA_BK0) );
psUDP->UDP_CSR &= ~(AT91C_UDP_RX_DATA_BK0);
KEYF_USB_SendZlp(psUDP);
break;
case GET_LINE_CODING:
KEYF_USB_SendData(psUDP, (char *) &line, Min(sizeof(line), wLength));
break;
case SET_CONTROL_LINE_STATE:
pskeyUSB->USBConnection = wValue;
KEYF_USB_SendZlp(psUDP);
break;
default:
KEYF_USB_SendStall(psUDP);
break;
}
}
/* Fuction ********************************************************************/
//名称: KEYF_USB_SendData
//功能: 通过端点0发送数据到主机
//参数: USB寄存器, 数据地址, 数据长度
//返回值: 无
//说明: 在配置USB期间,控制端点只能发送8字节数据,而且最多只发送8字节
/* Fuction ********************************************************************/
static void KEYF_USB_SendData ( AT91PS_UDP psUDP, const char *pData, uint length)
{
uint count = 0;
AT91_REG usb_csr;
do
{
count = Min(length, 8);
length -= count;
while ( count-- ) psUDP->UDP_FDR = *pData++;
if ( psUDP->UDP_CSR & AT91C_UDP_TXCOMP ) // 主机已经成功接收到数据
{
psUDP->UDP_CSR &= ~(AT91C_UDP_TXCOMP); // 清除标志
while ( psUDP->UDP_CSR & AT91C_UDP_TXCOMP );
}
psUDP->UDP_CSR |= AT91C_UDP_TXPKTRDY; // 固件通知外设数据入FIFO
do// 等待主机发"已经接收到数据信息" - (TXCOMP = 1)
{
usb_csr = psUDP->UDP_CSR;
if (usb_csr & AT91C_UDP_RX_DATA_BK0) // 外设"数据存入FIFO零"完成
{
psUDP->UDP_CSR &= ~(AT91C_UDP_RX_DATA_BK0);// 清除标志
return;
}
}while ( !(usb_csr & AT91C_UDP_TXCOMP) );
}while (length);
if (psUDP->UDP_CSR & AT91C_UDP_TXCOMP) // 发送完成后,清除TXCOMP标志a
{
psUDP->UDP_CSR &= ~(AT91C_UDP_TXCOMP);
while ( psUDP->UDP_CSR & AT91C_UDP_TXCOMP );
}
}
/* Fuction ********************************************************************/
//名称: KEYF_USB_SendZlp
//功能: 通过控制端点0发送零数据包
//参数: USB寄存器
//返回值: 无
//说明: 因为发送的是零长度包,所以不需要检测外设是否已经完成"数据入FIFO"
/* Fuction ********************************************************************/
void KEYF_USB_SendZlp ( AT91PS_UDP psUDP )
{
psUDP->UDP_CSR |= AT91C_UDP_TXPKTRDY;
while ( !(psUDP->UDP_CSR & AT91C_UDP_TXCOMP) );
psUDP->UDP_CSR &= ~(AT91C_UDP_TXCOMP);
while ( psUDP->UDP_CSR & AT91C_UDP_TXCOMP );
}
/* Fuction ********************************************************************/
//名称: KEYF_USB_SendStall
//功能: 停止控制端点
//参数: USB寄存器
//返回值: 无
//说明: 无
/* Fuction ********************************************************************/
void KEYF_USB_SendStall ( AT91PS_UDP psUDP )
{
psUDP->UDP_CSR |= AT91C_UDP_FORCESTALL;// 端点进入stall状态
while( !(psUDP->UDP_CSR & AT91C_UDP_ISOERROR) ); // 等待主机应答stall
psUDP->UDP_CSR &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);// 清除标志
while ( psUDP->UDP_CSR & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR) );
}
/* Fuction ********************************************************************/
//名称: KEYF_USB_Write
//功能: 通过"输入端点"发送数据
//参数: USB全局结构体, 数据地址, 数据长度
//返回值: 传输剩余长度length
//说明: 如果修改端点序号,请在"at91usb_conf.h"中直接修改"AT91C_IN_EP"
/* Fuction ********************************************************************/
static uintKEYF_USB_Write ( KEYS_USB *pskeyUSB, const char *pData, uint length )
{
AT91PS_UDPpsUDP = pskeyUSB->psUSB;
uint count = 0;
count = Min( length, AT91C_EP_IN_SIZE );// 发送第一个数据包
length -= count;
while (count--) psUDP->UDP_FDR = *pData++;
psUDP->UDP_CSR |= AT91C_UDP_TXPKTRDY;
while (length)
{
count = Min ( length, AT91C_EP_IN_SIZE );
length -= count;
while (count--) psUDP->UDP_FDR =*pData++;
while ( !(psUDP->UDP_CSR & AT91C_UDP_TXCOMP) ) // 等待主机完成数据接收
if ( !KEYF_IsUSBConfigured(pskeyUSB) ) return length;// 设备没有被配置
psUDP->UDP_CSR &= ~(AT91C_UDP_TXCOMP); // 清除标志
while ( psUDP->UDP_CSR & (AT91C_UDP_TXCOMP) );
psUDP->UDP_CSR |= AT91C_UDP_TXPKTRDY;// 通知数据准备发送到主机
}
while ( !(psUDP->UDP_CSR & AT91C_UDP_TXCOMP) ) // 等待主机应答
if ( !KEYF_IsUSBConfigured(pskeyUSB) ) return length;// 设备没有被配置
psUDP->UDP_CSR &= ~AT91C_UDP_TXCOMP;
while ( psUDP->UDP_CSR & AT91C_UDP_TXCOMP );
//KEYF_Toggle_LED ( LED2 );
AT91F_PIO_ClearOutput ( AT91C_BASE_PIOA, LED2 );
return length;
}
/* Fuction ********************************************************************/
//名称: KEYF_USB_Read
//功能: 通过"输出端点"接收数据
//参数: USB全局结构体, 数据地址, 数据地址
//返回值: 收到的数据
//说明: 如果修改端点序号,请在"at91usb_conf.h"中直接修改"AT91C_OUT_EP"
/* Fuction ********************************************************************/
static uintKEYF_USB_Read ( KEYS_USB *pskeyUSB, char *pData, uint length )
{
AT91PS_UDP psUDP = pskeyUSB->psUSB;
uint packetSize, nbBytesRcv = 0, currentReceiveBank = pskeyUSB->USBRcvBank;
while (length)
{
if ( !KEYF_IsUSBConfigured(pskeyUSB) ) // 设备没有配置好
break;
if ( psUDP->UDP_CSR & currentReceiveBank )// FIFO中收到数据包
{
packetSize = Min( psUDP->UDP_CSR >> 16, length); //
length -= packetSize;
if ( packetSize < AT91C_EP_OUT_SIZE )
length = 0;
while ( packetSize--)
pData = psUDP->UDP_FDR;
psUDP->UDP_CSR &= ~(currentReceiveBank);
if (currentReceiveBank == AT91C_UDP_RX_DATA_BK0) //
currentReceiveBank = AT91C_UDP_RX_DATA_BK1;
else
currentReceiveBank = AT91C_UDP_RX_DATA_BK0;
}
}
pskeyUSB->USBRcvBank = currentReceiveBank;
return nbBytesRcv;
} 回复【11楼】bj-stm8 珍惜生命 远离天_朝
-----------------------------------------------------------------------
很好的资料,LZ打个包一起发上来? 回复【25楼】eworker
回复【11楼】bj-stm8 珍惜生命 远离天_朝
-----------------------------------------------------------------------
很好的资料,lz打个包一起发上来?
-----------------------------------------------------------------------
不打包,因为有我们的应用程序在里面,需要剔除后才能发布 回复【26楼】bj-stm8 珍惜生命 远离天_朝
回复【25楼】eworker
回复【11楼】bj-stm8 珍惜生命 远离天_朝
-----------------------------------------------------------------------
很好的资料,lz打个包一起发上来?
-----------------------------------------------------------------------
不打包,因为有我们的应用程序在里面,需要剔除后才能发布
-----------------------------------------------------------------------
多发几个设计文档,其实文档意义更大些! 回复【27楼】eworker
-----------------------------------------------------------------------
多发几个设计文档,其实文档意义更大些!
-----------------------------------------------------------------------
是的,文档写好了很容易忽悠老板的。老板看到会感觉非常有成果。
如果你是做事直接读代码好了 回复【28楼】bj-stm8 珍惜生命 远离天_朝
回复【27楼】eworker
-----------------------------------------------------------------------
多发几个设计文档,其实文档意义更大些!
-----------------------------------------------------------------------
是的,文档写好了很容易忽悠老板的。老板看到会感觉非常有成果。
如果你是做事直接读代码好了
-----------------------------------------------------------------------
虽然有代码就是文档的说法,...... http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_604986XRDQJS.jpg
(原文件名:usb.jpg) mark mark mark 中通680108186766 发货11套zigbee,另外送AT91SAM7S64一套 mark, appreciate your great support! 大量AT91SAM7S64成品库存急需处理,欢迎联系 代码是程序员的文档,文档时BOSS的程序 深圳汪工,中通快递单号:201032362507
AT91SAM7S64,20片拆板芯片,请查收!
另外,为了让更多的坛友能得到芯片。10片也发货,10元一片 我觉得这个片子的库很烂 回复【37楼】kingsabbit 电子白菜
我觉得这个片子的库很烂
-----------------------------------------------------------------------
我觉得多数人要这个片子是为了搞jlink 谢谢。 这个模块又有10套了,带塑料外壳,测试完好,提供源代码,每个49元! mark mark . 怎么交易啊 还有吗 楼主?? 淘宝联系,年后发货
页:
[1]