mohan-bee/mini-mp3-player

Portable, battery-powered MP3 player hardware with USB charging, microSD storage, an MCU, VS10xx audio decoder, headphone output, status controls, and regulated power rails.

Version
1.2.0
License
unset
Stars
0

firmware/src/diskio.c

#include "board.h"
#include "ff.h"
#include "diskio.h"
static DSTATUS status=STA_NOINIT;
static bool block_addressing;
static bool transfer_ok;
static uint8_t exchange(uint8_t tx) {
    uint8_t rx=0xff;
    if (!sd_byte(tx,&rx)) transfer_ok=false;
    return rx;
}
static void release_card(void) { sd_select(false); exchange(0xff); }
static bool ready(uint32_t timeout) {
    uint32_t start=millis();
    do { if (exchange(0xff)==0xff && transfer_ok) return true; }
    while (transfer_ok && (uint32_t)(millis()-start)<timeout);
    return false;
}
static uint8_t command(uint8_t cmd,uint32_t arg) {
    release_card(); sd_select(true);
    if (!ready(250)) return 0xff;
    exchange(0x40|cmd);
    exchange((uint8_t)(arg>>24)); exchange((uint8_t)(arg>>16));
    exchange((uint8_t)(arg>>8)); exchange((uint8_t)arg);
    exchange(cmd==0 ? 0x95 : cmd==8 ? 0x87 : 0x01);
    for (unsigned i=0;i<10;i++) {
        uint8_t response=exchange(0xff);
        if (!(response & 0x80) && transfer_ok) return response;
    }
    return 0xff;
}
DSTATUS disk_initialize(BYTE drive) {
    if (drive) return STA_NOINIT;
    status=STA_NOINIT; block_addressing=false; transfer_ok=true;
    sd_speed(false); sd_select(false); delay_ms(20);
    for (unsigned i=0;i<10;i++) exchange(0xff);
    if (command(0,0)!=1) goto finish;
    uint8_t r=command(8,0x1aa);
    bool v2=r==1;
    if (v2) {
        uint8_t r7[4]; for(unsigned i=0;i<4;i++) r7[i]=exchange(0xff);
        if (r7[2]!=1 || r7[3]!=0xaa) goto finish;
    } else if (r!=5) goto finish; // SD v1 may reject CMD8 as illegal.
    uint32_t start=millis();
    do {
        if (command(55,0)>1) goto finish;
        r=command(41,v2 ? 0x40000000 : 0);
        if (!r) break;
        if (r!=1) goto finish;
        delay_ms(1);
    } while ((uint32_t)(millis()-start)<1500);
    if (r) goto finish;
    if (command(58,0)) goto finish;
    uint8_t ocr[4]; for(unsigned i=0;i<4;i++) ocr[i]=exchange(0xff);
    if (!(ocr[0]&0x80)) goto finish;
    block_addressing=v2 && (ocr[0]&0x40);
    if (!block_addressing && command(16,512)) goto finish;
    if (transfer_ok) { status=0; sd_speed(true); }
finish:
    release_card(); return status;
}
DSTATUS disk_status(BYTE drive) { return drive ? STA_NOINIT : status; }
DRESULT disk_read(BYTE drive,BYTE *buffer,LBA_t sector,UINT count) {
    if (drive || !count) return RES_PARERR;
    if (status & STA_NOINIT) return RES_NOTRDY;
    transfer_ok=true;
    while(count--) {
        if (command(17,block_addressing ? sector : sector*512u)) goto failed;
        uint32_t start=millis(); uint8_t token;
        do { token=exchange(0xff); }
        while(token==0xff && transfer_ok && (uint32_t)(millis()-start)<250);
        if (token!=0xfe || !transfer_ok) goto failed;
        for(unsigned i=0;i<512;i++) *buffer++=exchange(0xff);
        exchange(0xff); exchange(0xff); // SPI-mode data CRC disabled by default.
        if (!transfer_ok) goto failed;
        release_card(); sector++;
    }
    return RES_OK;
failed:
    release_card(); status=STA_NOINIT; return RES_ERROR;
}
DRESULT disk_ioctl(BYTE drive,BYTE cmd,void *buffer) {
    (void)buffer;
    if (drive) return RES_PARERR;
    if (status & STA_NOINIT) return RES_NOTRDY;
    if (cmd==CTRL_SYNC) return RES_OK;
    return RES_PARERR; // Read-only FatFs does not require size/erase commands.
}