📄 ch375.c
字号:
#include <stdio.h>
#include "ch375.h"
#include "CH375INC.h"
#include "AT91SAM7S64.h"
#include "lib_AT91SAM7S64.h"
#include "diskio.h"
#define UINT8 unsigned char
#define UINT16 unsigned short
#define UINT32 unsigned long
#define UINT8X unsigned char
#define UINT8VX unsigned char volatile
#define USB_DELAY1 60UL
#define USB_DELAY2 60UL
#define USE_HWPRESET 1
#if USE_HWPRESET > 0
#define CH375_HW_RST (1 << 29)
#define CH375_RST_H() AT91C_BASE_PIOA->PIO_SODR |= CH375_HW_RST
#define CH375_RST_L() AT91C_BASE_PIOA->PIO_CODR |= CH375_HW_RST
#else
#define CH375_RST_H()
#define CH375_RST_L()
#endif
/* IO PIN */
#define CH375_ADD_LE (1 << 8 ) /* PA8: Address Latch */
#define CH375_nRD (1 << 24) /* PA24: /Read */
#define CH375_nWR (1 << 25) /* PA25: /Write */
#define CH375_INT_WIRE (1 << 26) /* PA26: 连接CH375的INT#引脚,用于查询中断状态 */
/* Address */
#define CH375_CMD_EN (0x7F)
#define CH375_DAT_EN (0x7E)
/* IO MACRO */
#define RD_H() AT91C_BASE_PIOA->PIO_SODR |= CH375_nRD
#define RD_L() AT91C_BASE_PIOA->PIO_CODR |= CH375_nRD
#define WR_H() AT91C_BASE_PIOA->PIO_SODR |= CH375_nWR
#define WR_L() AT91C_BASE_PIOA->PIO_CODR |= CH375_nWR
#define LE_H() AT91C_BASE_PIOA->PIO_SODR |= CH375_ADD_LE
#define LE_L() AT91C_BASE_PIOA->PIO_CODR |= CH375_ADD_LE
#define CH375_BUS_IN() AT91C_BASE_PIOA->PIO_ODR |= 0xFF
#define CH375_BUS_OUT() AT91C_BASE_PIOA->PIO_OER |= 0xFF
#define CH375_DAT_GET() AT91C_BASE_PIOA->PIO_PDSR & 0xFF
#define CH375_INT_STATE() (AT91C_BASE_PIOA->PIO_PDSR & (1 << 26))
/* output data on IO pin to CH375 data bus */
#define CH375_OUT(dat) AT91C_BASE_PIOA->PIO_ODSR = dat & 0xFF
UINT32 DiskStart = 0; /* 逻辑盘的起始绝对扇区号LBA */
UINT8 SecPerClus = 0; /* 逻辑盘的每簇扇区数 */
UINT8 RsvdSecCnt = 0; /* 逻辑盘的保留扇区数 */
UINT16 FATSz16 = 0; /* FAT16逻辑盘的FAT表占用的扇区数 */
unsigned char USB_Stat = STA_NOINIT;
/***************************************************************************************/
/* HW init */
static CH375_IO_Init(void)
{
AT91PS_PIO pPIOA = AT91C_BASE_PIOA;
// enbale Pins as IO
pPIOA->PIO_PER = CH375_INT_WIRE | CH375_nWR | CH375_nRD | 0x1FF; /* PA8, PA7 ~ PA0 */
// WR, RD, DATA, LE output
pPIOA->PIO_OER = CH375_nWR | CH375_nRD | 0x1FF; /* PA8, PA7 ~ PA0 */
// disable CS RD
pPIOA->PIO_SODR = CH375_nWR | CH375_nRD;
// write IO directly
pPIOA->PIO_OWER |= 0xFF;
// enable Pull-UP
//pPIOA->PIO_PPUER = CH375_INT_WIRE | CH375_nWR | CH375_nRD | 0x1FF; /* PA8, PA7 ~ PA0 */
// INT input
pPIOA->PIO_ODR = CH375_INT_WIRE;
// filter
pPIOA->PIO_IFER = CH375_INT_WIRE;
#if USE_HWPRESET > 0
pPIOA->PIO_PER |= CH375_HW_RST;
pPIOA->PIO_OER |= CH375_HW_RST;
/* RESET = H, reset CH375 */
pPIOA->PIO_SODR |= CH375_HW_RST;
#endif
// enable input, enbale PIOA clock
AT91F_PIOA_CfgPMC();
}
/***************************************************************************************/
/* delay functions */
static void mDelaymS( unsigned short ms )
{
signed short i, j;
for ( i = ms; i > 0; i -- )
{
for ( j = 25000; j > 0; j -- );
}
}
/* delay functions */
static void mDelayuS( unsigned short us )
{
#if 0
signed short i, j;
for ( i = us; i > 0; i -- )
{
for ( j = 60; j > 0; j -- );
}
#else
while(us > 0) us--;
#endif
}
/***************************************************************************************/
/* Send command */
static void CH375_WR_CMD_PORT( UINT8 cmd )
{
/* 向CH375的命令端口写入命令 */
RD_H();
WR_H();
LE_L();
CH375_BUS_OUT();
mDelayuS ( 10 );
CH375_OUT(CH375_CMD_EN); /* select CMD port */
LE_H(); /* latch address */
mDelayuS ( 10 );
LE_L();
mDelayuS ( 10 );
CH375_OUT(cmd); /* output command */
WR_L();
mDelayuS ( 15 ); /* 90nS < TWW < 10000nS */
WR_H();
mDelayuS ( 15 );
}
/* write DATA */
static void CH375_WR_DAT_PORT( UINT8 dat )
{
/* 向CH375的数据端口写入数据 */
RD_H();
WR_H();
LE_L();
CH375_BUS_OUT();
mDelayuS ( 10 );
CH375_OUT(CH375_DAT_EN); /* select CMD port */
LE_H(); /* latch address */
mDelayuS ( 10 );
LE_L();
mDelayuS ( 10 );
CH375_OUT(dat); /* output command */
WR_L();
mDelayuS ( 15 ); /* 90nS < TWW < 10000nS */
WR_H();
mDelayuS ( 10 );
}
/* read DATA */
static UINT8 CH375_RD_DAT_PORT( void )
{
UINT8 dat = 0;
/* 从CH375的数据端口读出数据 */
/* 向CH375的命令端口写入命令 */
RD_H();
WR_H();
LE_L();
CH375_BUS_OUT();
mDelayuS ( 10 );
CH375_OUT(CH375_DAT_EN); /* select CMD port */
LE_H(); /* latch address */
mDelayuS ( 10 );
LE_L();
mDelayuS ( 10 );
/* data bus change to input mode */
CH375_BUS_IN();
RD_L();
mDelayuS ( 20 ); /* 90nS < TRW < 10000nS */
dat = CH375_DAT_GET();
RD_H();
mDelayuS ( 10 );
return dat;
}
static UINT8 mWaitInterrupt( void )
{
unsigned char status = 0;
signed long timeout = 10000;
//mDelaymS( 30 );
/* 等待CH375中断并获取状态,返回操作状态 */
while( CH375_INT_STATE() && (timeout > 0)) timeout --; /* 查询等待CH375操作完成中断(INT#低电平) */
mDelayuS( 3000 );
CH375_WR_CMD_PORT( CMD_GET_STATUS ); /* 产生操作完成中断,获取中断状态 */
mDelayuS( 10 );
status = CH375_RD_DAT_PORT( );
return status;
}
/* ********** BulkOnly传输协议层,被CH375内置了,无需编写单片机程序 */
/* ********** RBC/SCSI命令层,虽然被CH375内置了,但是要写程序发出命令及收发数据 */
UINT8 mReadSector( UINT32 iLbaStart, UINT8 iSectorCount, UINT8X *oDataBuffer )
{
UINT16 mBlockCount = 0;
UINT8 sct = iSectorCount;
UINT8 c = 0xFF;
CH375_WR_CMD_PORT( CMD_DISK_READ ); /* 从USB存储器读数据块 */
CH375_WR_DAT_PORT( (UINT8)( iLbaStart) ); /* LBA的最低8位 */
CH375_WR_DAT_PORT( (UINT8)( iLbaStart >> 8 ) );
CH375_WR_DAT_PORT( (UINT8)( iLbaStart >> 16 ) );
CH375_WR_DAT_PORT( (UINT8)( iLbaStart >> 24 ) ); /* LBA的最高8位 */
CH375_WR_DAT_PORT( sct ); /* 扇区数 */
mDelayuS( 0 );
for ( mBlockCount = sct * 8; mBlockCount != 0; mBlockCount -- )
{
c = mWaitInterrupt( ); /* 等待中断并获取状态 */
if ( c == USB_INT_DISK_READ )
{ /* 等待中断并获取状态,请求数据读出 */
CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 从CH375缓冲区读取数据块 */
c = CH375_RD_DAT_PORT( ); /* 后续数据的长度 */
while ( c -- ) *oDataBuffer++ = CH375_RD_DAT_PORT( );
mDelayuS( 3000 );
CH375_WR_CMD_PORT( CMD_DISK_RD_GO ); /* 继续执行USB存储器的读操作 */
}
else
{
c = mWaitInterrupt( ); /* 等待中断并获取状态 */
break; /* 返回错误状态 */
}
}
if ( 0 == mBlockCount)
{
c = mWaitInterrupt( ); /* 等待中断并获取状态 */
//mDelaymS( 3 );
c = mWaitInterrupt( ); /* 等待中断并获取状态 */
if ( c== USB_INT_SUCCESS )
return( 0 ); /* 操作成功 */
}
return( c ); /* 操作失败 */
}
UINT8 mInitDisk( void )
{
/* 初始化磁盘 */
UINT8 Status = 0;
UINT8 buf[10] = {0};
UINT8 i = 0;
CH375_WR_CMD_PORT( CMD_GET_STATUS ); /* 产生操作完成中断, 获取中断状态 */
Status = CH375_RD_DAT_PORT( );
mDelaymS( 100 );
if ( Status == USB_INT_DISCONNECT ) return( Status ); /* USB设备断开 */
/* U 盘已连接 */
mDelaymS( 100 ); /* 延时,可选操作,有的USB存储器需要几十毫秒的延时 */
CH375_WR_CMD_PORT( CMD_DISK_INIT ); /* 初始化USB存储器 */
mDelaymS( 100 );
Status = mWaitInterrupt( ); /* 等待中断并获取状态 */
mDelaymS( 100 );
if ( Status != USB_INT_SUCCESS ) return( Status ); /* 出现错误 */
#if 1
CH375_WR_CMD_PORT( CMD_DISK_SIZE ); /* 获取USB存储器的容量 */
Status = mWaitInterrupt( ); /* 等待中断并获取状态 */
if ( Status != USB_INT_SUCCESS )
{ /* 出错重试 */
/* 对于CH375A芯片,建议在此执行一次CMD_DISK_R_SENSE命令 */
mDelaymS( 50 );
CH375_WR_CMD_PORT( CMD_DISK_SIZE ); /* 获取USB存储器的容量 */
Status = mWaitInterrupt( ); /* 等待中断并获取状态 */
}
if ( Status != USB_INT_SUCCESS ) return( Status ); /* 出现错误 */
CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 从CH375缓冲区读取数据块 */
for (i = 0; i < 9; i++)
{
//mDelaymS( 10 );
buf[i] = CH375_RD_DAT_PORT( ); /* 后续数据 */
}
#endif
return( 0 ); /* U盘已经成功初始化 */
}
/***************************************************************************************/
unsigned char CH375_Init(void)
{
unsigned char t = 0;
unsigned char res = 0;
CH375_IO_Init();
#if USE_HWPRESET > 0
CH375_RST_H();
mDelaymS( 100 );
CH375_RST_L();
mDelaymS( 100 );
#endif
CH375_WR_CMD_PORT(CMD_RESET_ALL); /* reset CH375, 40ms */
mDelaymS( 1000 ); /* 延时等待U盘进入正常工作状态 */
t = 0x55;
CH375_WR_CMD_PORT(CMD_CHECK_EXIST); /* test CH375 */
CH375_WR_DAT_PORT(t);
t = ~t;
res = CH375_RD_DAT_PORT();
if (res != t)
{
while(1); /* CH375 no resonese */
}
CH375_WR_CMD_PORT( CMD_SET_USB_MODE ); /* 初始化CH375,设置USB工作模式 */
CH375_WR_DAT_PORT( 6 ); /* 模式代码,自动检测USB设备连接 */
mDelaymS( 10 ); /* 延时等待U盘进入正常工作状态 */
res = mInitDisk( ); /* 初始化U盘,实际是识别U盘的类型,必须进行此步骤 */
return res;
}
/*=======================================================================*/
/* Public Functions */
/*=======================================================================*/
/*-----------------------*/
/* Initialize Disk Drive */
DSTATUS USB_disk_initialize (void)
{
unsigned char res = 0;
res = CH375_Init();
switch (res)
{
case USB_INT_DISCONNECT:
USB_Stat = STA_NODISK;
break;
case 0:
USB_Stat &= ~STA_NOINIT; /* When device goes ready, clear STA_NOINIT */
default:
break;
}
return USB_Stat;
}
/*--------------------*/
/* Return Disk Status */
DSTATUS USB_disk_status (void)
{
return USB_Stat;
}
/*--------------------------*/
/* Miscellaneous Functions */
DRESULT USB_disk_ioctl (
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive data block */
)
{
DRESULT stat = 0;
unsigned char res = 0;
unsigned char i = 0;
unsigned char *dat = (unsigned char *)buff;
if (USB_Stat & STA_NOINIT) return RES_NOTRDY;
switch(ctrl)
{
case USB_GET_SIZE:
CH375_WR_CMD_PORT( CMD_DISK_INIT ); /* 初始化USB存储器 */
res = mWaitInterrupt( ); /* 等待中断并获取状态 */
if ( res != USB_INT_SUCCESS ) /* 出现错误 */
{
break;
}
CH375_WR_CMD_PORT( CMD_DISK_SIZE ); /* 获取USB存储器的容量 */
res = mWaitInterrupt( ); /* 等待中断并获取状态 */
if (USB_INT_SUCCESS == res)
{
for (i =0; i < 9; i++)
{
*dat = CH375_RD_DAT_PORT();
dat++;
}
}
break;
default:
break;
}
return stat;
}
/*----------------*/
/* Read Sector(s) */
DRESULT USB_disk_read (
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
DRESULT stat = RES_ERROR;
unsigned char res = 0;
res = mReadSector(sector, count, buff);
if(!res) stat = RES_OK;
return stat;
}
/*-----------------*/
/* Write Sector(s) */
#if _READONLY == 0
DRESULT USB_disk_write (
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
DRESULT stat = 0;
return stat;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -