CY7C68031A固件程序FW.C详解(1)
来源:互联网 发布:淘宝互刷平台2016 编辑:程序博客网 时间:2024/06/05 05:40
////本来要一次传上去,百度空间嫌文章太长,只好分为两篇
////FW.C文件,我当初看了一个星期,也没看懂的。这里我们逐字逐句研读,
////边理解,边一行一行的注释.
//////以下是Cypress公司的官方程序,我不做改动,原英文注释保留,只增加注释
//简单语句就不说了
//// //???//是我不懂得的地方,希望高手补充
//// //###//是以后开发可能需要改动的地方//
////我加的所有注释都用////四个连斜杠,便于以后不需要的时候屏蔽掉
////这是在Keil UV2里编辑的,没有其它格式字符,可以直接编译
//-----------------------------------------------------------------------------
// File: fw.c
// Contents: Firmware frameworks task dispatcher and device request parser
//
// $Archive: /USB/Examples/FX2LP/bulkext/fw.c $
// $Date: 3/23/05 2:53p $
// $Revision: 8 $
//
//
//-----------------------------------------------------------------------------
// Copyright 2003, Cypress Semiconductor Corporation
//-----------------------------------------------------------------------------
#include "fx2.h"
////fx2.h 定义EZUSB的宏、数据类型等的头文件
#include "fx2regs.h"
////fx2regs.h 定义EZUSB寄存器定义的头文件
#include "syncdly.h" // SYNCDELAY macro
////syncdly.h 同步延时宏定义
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
#define DELAY_COUNT 0x9248*8L // Delay for 8 sec at 24Mhz, 4 sec at 48
#define _IFREQ 48000 // IFCLK constant for Synchronization Delay
#define _CFREQ 48000 // CLKOUT constant for Synchronization Delay
////以上设置时钟频率为48MHZ
//-----------------------------------------------------------------------------
// Random Macros
//-----------------------------------------------------------------------------
#define min(a,b) (((a)<(b))?(a):(b))
#define max(a,b) (((a)>(b))?(a):(b))
//-----------------------------------------------------------------------------
// Global Variables
////全局变量
//-----------------------------------------------------------------------------
volatile BOOL GotSUD;
////GotSUD是令牌包标志,准确的说是“令牌阶段数据到来”,什么是令牌包?
////首先,USB一连串的数据传输、处理、响应等就叫做USB事务。
////例如,上位机要读取一个描述符,那么就会触发一次USB事务。
////一个完整的USB事务处理有三个阶段:令牌阶段,数据阶段,握手阶段。
////每个阶段数据传输是有各种包组成的,例如令牌阶段:同步字段+令牌包+EOP构成。
////USB主机启动事务处理,开始发送令牌包,这个时候假如说我们当前的USB设备地址号
////为2(重枚举时分配的),而主机发送的地址号也为2,那么这个USB设备硬件会产生
////中断,进入中断处理。也就是periph.c文件中的void ISR_Sudav(void)函数,
////在这个中断处理中,设置 GotSUD标志为TRUE,表示收到令牌数据,要启动USB传输了。
////然后我们固件中判断if(GotSUD),GotSUD为真,则执行SetupCommand()函数,
////在这里处理控制传输,读取描述符,设置特性,处理Vendor命令等。
////完毕后置GotSUD = FALSE;然后检查USB各种状态并处理:
BOOL Rwuen;
////Rwuen 远程唤醒标志
BOOL Selfpwr;
////Selfpwr 禁止或使能自供电模式
volatile BOOL Sleep; // Sleep mode enable flag
////Sleep //禁止或使能休眠模式
////以下是定向USB描述符
WORD pDeviceDscr; // Pointer to Device Descriptor; Descriptors may be moved
////设备描述符指针
WORD pDeviceQualDscr;
////设备限定描述符指针
WORD pHighSpeedConfigDscr;
////高速配置描述符指针
WORD pFullSpeedConfigDscr;
////全速配置描述符指针
WORD pConfigDscr;
////配置描述符指针
WORD pOtherConfigDscr;
////其他速率配置描述指针
WORD pStringDscr;
////字符串描述符指针
//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
////硬件程序的函数入口。主要有以下这些方法:
////功能在函数中说明
void SetupCommand(void);
////void SetupCommand(void); //握手命令处理
void TD_Init(void);
////void TD_Init(void); //初始化,完成配置,启动时调用一次
void TD_Poll(void);
////void TD_Poll(void); //用户处理程序,循环调用
////void IO_Init(void); //8051 IO初始化
////void REG_Init(void); //8051寄存器初始化
BOOL TD_Suspend(void);
////BOOL TD_Suspend(void); //挂起处理
BOOL TD_Resume(void);
////BOOL TD_Resume(void); //唤醒处理
////以下为各种描述符的获取和设置函数,重枚举时自动调用
////功能在函数中说明
BOOL DR_GetDescriptor(void);
////DR_GetDescriptor(void)获得描述符
BOOL DR_SetConfiguration(void);
//// BOOL DR_SetConfiguration(void)设置配置子函数
BOOL DR_GetConfiguration(void);
////BOOL DR_GetConfiguration(void) 获取配置子函数
BOOL DR_SetInterface(void);
//// DR_SetInterface(void)配置接口子函数
BOOL DR_GetInterface(void);
//// DR_GetInterface(); 获取接口子函数
BOOL DR_GetStatus(void);
/////DR_GetStatus(void) 获得状态
BOOL DR_ClearFeature(void);
////DR_ClearFeature(void) 清除特性
BOOL DR_SetFeature(void);
////DR_SetFeature(void)设置特性
BOOL DR_VendorCmnd(void);
//// DR_VendorCmnd(void) 自定义的用户请求
// this table is used by the epcs macro
//// //???//
const char code EPCS_Offset_Lookup_Table[] =
{
0, // EP1OUT
1, // EP1IN
2, // EP2OUT
2, // EP2IN
3, // EP4OUT
3, // EP4IN
4, // EP6OUT
4, // EP6IN
5, // EP8OUT
5, // EP8IN
};
// macro for generating the address of an endpoint's control and status register (EPnCS)
//// //???//
#define epcs(EP) (EPCS_Offset_Lookup_Table[(EP & 0x7E) | (EP > 128)] + 0xE6A1)
//-----------------------------------------------------------------------------
// Code
//-----------------------------------------------------------------------------
// Task dispatcher
void main(void)
{
DWORD i;
WORD offset;
DWORD DevDescrLen;
DWORD j=0;
WORD IntDescrAddr;
WORD ExtDescrAddr;
// Initialize Global States
////初始化全局状态变量
Sleep = FALSE; // Disable sleep mode
////Sleep = FALSE; //初始化用户变量 休眠使能--禁止
Rwuen = FALSE; // Disable remote wakeup
////Rwuen = FALSE;//远程唤醒--禁止
Selfpwr = FALSE; // Disable self powered
////Selfpwr = FALSE; //禁止自供电模式
GotSUD = FALSE; // Clear "Got setup data" flag
////GotSUD = FALSE; //清除SetUp令牌包到来标志
// Initialize user device
TD_Init();
////TD_Init(); 初始化USB
// The following section of code is used to relocate the descriptor table.
// The frameworks uses SUDPTRH and SUDPTRL to automate the SETUP requests
// for descriptors. These registers only work with memory locations
// in the EZ-USB internal RAM. Therefore, if the descriptors are located
// in external RAM, they must be copied to in internal RAM.
// The descriptor table is relocated by the frameworks ONLY if it is found
// to be located in external memory.
//取得定向USB描述符的指针(地址)
//这段代码用来获取USB的各个描述符在68013内存中的地址,
//准确说是在RAM中的地址,在dscrpt.a51文件中有定义,
//所有的描述符组成了整个的描述符表,后面会用到。
pDeviceDscr = (WORD)&DeviceDscr;
////pDeviceDscr = (WORD)&DeviceDscr; //设备描述符
pDeviceQualDscr = (WORD)&DeviceQualDscr;
//// pDeviceQualDscr = (WORD)&DeviceQualDscr; //设备限定描述符
pHighSpeedConfigDscr = (WORD)&HighSpeedConfigDscr;
//// pHighSpeedConfigDscr = (WORD)&HighSpeedConfigDscr; //高速配置描述符
pFullSpeedConfigDscr = (WORD)&FullSpeedConfigDscr;
//// pFullSpeedConfigDscr = (WORD)&FullSpeedConfigDscr; //全速配置描述符
pStringDscr = (WORD)&StringDscr;
//// pStringDscr = (WORD)&StringDscr; //字符串描述符
// Is the descriptor table in external RAM (> 16Kbytes)? If yes,
// then relocate.
// Note that this code only checks if the descriptors START in
// external RAM. It will not work if the descriptor table spans
// internal and external RAM.
////意思是说,这段代码用来判断描述符表首址,
////也就是前面的DeviceDscr、DeviceQualDscr等是否位于68013的外部RAM区,
////如果是,则移除,然后将描述符表移到内部RAM区,为什么要移到内部RAM区,
////因为当描述符表位于外部RAM时,USB是不工作的。那么如何判断描述符地址
////是否超出内部RAM的地址呢?首先,&DeviceDscr取得整个描述符表的首地址
////(它也是DeviceDscr设备描述的首址),然后和0XC000相与,为什么要和0XC000相与?
////这就牵涉到68013 FX2LP(注意是LP)的内部结构图:
////见数据单
////上图针对的是128pin的FX2LP,如果是56或100pin的,那么没有外部RAM,
////只有内部RAM。可以看到,FX2LP内部RAM从0000-FFFF,其他为外部RAM。
////而内部RAM中,只有从0000-3FFF和从E000-FFFF的区域可用,其他为系统保留。
////从0000-3FFF这16K bytes的内部RAM空间,叫做主RAM,对56,100,128pin来说,
////都可以同时作为程序或数据存储器(对128pin来说,EA=0)。
////再看&DeviceDscr & 0xC000的结果,要为“真”的话,显然,
////必须&DeviceDscr>=0X4000,也就是说判断的是描述表首址&DeviceDsc是否大于3FFF,
////刚好是主RAM区的大小,这就是为什么要用&DeviceDscr 和 0xC000相与就来
////判断实现了描述符表首地址的原因了(外部 or 内部 ram?)
if ((WORD)&DeviceDscr & 0xC000)
{
// first, relocate the descriptors
IntDescrAddr = INTERNAL_DSCR_ADDR;
ExtDescrAddr = (WORD)&DeviceDscr;
DevDescrLen = (WORD)&UserDscr - (WORD)&DeviceDscr + 2;
for (i = 0; i < DevDescrLen; i++)
*((BYTE xdata *)IntDescrAddr+i) = *((BYTE xdata *)ExtDescrAddr+i);
////判断发现描述符表首址位于外部RAM的后,紧接着就将外部RAM的描述符移到内部RAM。
//////这里就用到了前面定义的变量,IntDescrAddr保存内部RAM首址0X80,
////ExtDescrAddr保存我们获得的当前描述符表外部RAM的首址 ,DevDescrLen
//////是整个描述表的长度,从DeviceDscr段到UserDscr段,在dscrptr中有定义。
//然后for循环,将从ExtDescrAddr地址开始的外部RAM中的数据逐个copy到从
////IntDescrAddr地址开始的内部RAM区。
// update all of the descriptor pointers
//// 更新描述符指针
////完毕后更新描述符指针,指向内部RAM区,通过原指针减去一个偏移量得到。
pDeviceDscr = IntDescrAddr;
offset = (WORD)&DeviceDscr - INTERNAL_DSCR_ADDR;
pDeviceQualDscr -= offset;
pConfigDscr -= offset;
pOtherConfigDscr -= offset;
pHighSpeedConfigDscr -= offset;
pFullSpeedConfigDscr -= offset;
pStringDscr -= offset;
}
EZUSB_IRQ_ENABLE(); // Enable USB interrupt (INT2)
//// EZUSB中断使能
////EZUSB_IRQ_ENABLE();预定义是EZUSB=1,ezusb是EIE寄存器的第0位,EIE.0=1,使能USB中断;
EZUSB_ENABLE_RSMIRQ(); // Wake-up interrupt
////使能远程唤醒中断
////EZUSB_ENABLE_RSMIRQ();EICON |= 0x20,EICON.5=1,使能远程唤醒中断;
INTSETUP |= (bmAV2EN | bmAV4EN); // Enable INT 2 & 4 autovectoring
////使能INT2,4自动向量跳转
////INTSETUP |= (bmAV2EN | bmAV4EN);使能INT2,4自动向量跳转;
USBIE |= bmSUDAV | bmSUTOK | bmSUSP | bmURES | bmHSGRANT; // Enable selected interrupts
//// 使能所选择中断
////相关的中断意义,后面慢慢学习补充;
EA = 1; // Enable 8051 interrupts
//// 开8051中断
#ifndef NO_RENUM
// Renumerate if necessary. Do this by checking the renum bit. If it
// is already set, there is no need to renumerate. The renum bit will
// already be set if this firmware was loaded from an eeprom.
if (!(USBCS & bmRENUM)) //如果RENUM位为0,则重列举
{
EZUSB_Discon(TRUE); // renumerate 重列举
}
#endif
////这段代码即告诉USB进行重枚举,用软件设置,模拟USB断开与连接,
////EZUSB_Discon(TRUE)完成断开连接
////将USBCS寄存器的DICON位置1,断开USB,同时如果RENUM位为0,
////则置1;然后重新连接USB。
////那么,什么是重枚举呢?
////首先,上面的USB枚举是对通用USB来说的,一般USB设备只有枚举过程,没有重枚举过程。
////也就是说其实,对EZ-USB系列来说,上面的枚举举实际包含了EZ-USB枚举和重枚举
////两个过程:
////对EZ-USB来说,枚举过程就是USB上电复位到加载固件前这段过程,此时USB设备
////地址号为默认的0号,枚举完成后,驱动为cypress...eeprom..missing
////(FX2/FX2LP来说)。然后加载固件,进行重枚举,重枚举完成后,
////显示驱动为cypress...ez-usb...example或其他自定义设备。
////为什么EZ-USB有重枚举过程呢?这就是为了可以让主机在前期固件未加载前自动枚举,
////识别USB,从而可以从上位机加载固件到68013的RAM中,而无需使用ROM,EEPROM,
////FLASH等内存。实现“软件”架构加载程序代码,随时修改固件。
////EZ-USB如何控制重枚举?
////首先,EZUSB有一个寄存器USBCS,其中第1位USBCS.1为Renum控制枚举重枚举。
////在USB上电未加载固件代码前,Renum=0,表示使用“EZUSB核心”对芯片的初始配置,
////处理主机设备请求,并负责把固件下载到RAM中,这个过程就是“枚举”,
////完成该枚举过程的设备叫做“缺省USB设备(地址号0)”,
////即驱动显示为“...missing”的设备。当固件被下载到8051 RAM后,此时Renum=1,
////表示使用“增强8051核心”处理主机设备请求,并按照固件的代码(读取所有描述符)
////重新配置USB设备,这个过程就叫做“重枚举”,完成重枚举后,
////显示自定义的USB设备“...example”,实际是模拟断开与连接的过程。
////用以下表表示:
////事件----处理设备请求--Renum-----8051动作
////枚举----EZUSB核心-----Renum=0--8051置Renum=1
////重枚举--8051----------Renum=1--8051重置Renum=0
////在重枚举完成后,对控制端点0的设备请求可以由“EZUSB核心”处理或由
////“增强8051核心”处理,有Renum的值决定。芯片上电时Renum=0,
////由“EZUSB核心”处理;一旦8051开始运行,就可以设置Renum=1,
////由“增强8051核心”处理,表示按照8051下载的固件代码处理。
////当然,这时也可以设置Renum=0,让“EZUSB核心”处理端点0的设备请求,
////而让8051完成具体的USB数据传输,这样做会大大简化8051固件代码。
////然后再看接下来的代码:
////注意,在这段代码之前,EZUSB已经枚举完成,当然,整个过程是自动的,
////我们看不见的。
//// 详见<<USB设备枚举过程.doc>>
// unconditionally re-connect. If we loaded from eeprom we are
// disconnected and need to connect. If we just renumerated this
// is not necessary but doesn't hurt anything
USBCS &=~bmDISCON;
////重新连接
CKCON = (CKCON&(~bmSTRETCH)) | FW_STRETCH_VALUE; // Set stretch
// CKCON = (CKCON&(~bmSTRETCH)) | FW_STRETCH_VALUE;Set stretch to 0 (after renumeration)
//EZ-USB执行指令MOVX(读取外部存储器)时,在两个MOVX之间可以增加的几个时钟周期数
//这对于外部的较慢的存储器或外设(例如LCD)等是很合适的,外部存储器的等待时钟可以在固件中调整
//但是程序存储器不会受到影响
// clear the Sleep flag.
Sleep = FALSE;
////清sleep休眠使能标志
//紧接着主机开始读描述符,并进行配置(发送SetConfiguration),
//加载驱动等,完成重枚举。
- CY7C68031A固件程序FW.C详解(1)
- CY7C68031A固件程序FW.C详解(2)
- FW(固件)库函数RCC_GetClocksFreq()
- [ M3 LN ] FW(固件)库函数USART_Init()
- [ M3 LN ] FW(固件)库函数RCC_GetClocksFreq()
- [ M3 LN ] FW(固件)库函数NVIC_Xxx()
- [ M3 LN ] FW(固件)库函数SystemInit() (72MHz)
- FW:看程序学OpenCV(1)
- FW: FTP命令详解
- FW:理解矩阵(三)(1)
- usb68013Bulkloop固件程序
- fw
- CY7C68031A驱动安装注意事项
- 嵌入式程序和FW的区别
- FW:看程序学OpenCV(2)
- FW:HTTP POST GET 本质区别详解
- [FW]C Coding Standards Quick Reference
- FW:C# 视频监控系列
- Bit movement operation
- python IE自动化模块(模拟操作IE)
- 在线阅读
- 图像识别技术发展趋势分析
- python用浏览器打开网页的两种方式
- CY7C68031A固件程序FW.C详解(1)
- 基于内容的视频分析与检索技术及其教学应用
- 完成strcpy函数的功能//传入的指针可以使用数组的方式赋值
- CY7C68031A固件程序FW.C详解(2)
- 淘宝大规模数据库
- c#中的委托详解
- wofstream 输出CString Unicode|路径中文名支持
- IE首页被篡改
- python实现的dos窗口播放器