⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch375.c

📁 S64和VS1003的MP3播放实现的源代码/
💻 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 + -