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/decoder.c

#include "board.h"
#include "decoder.h"
static bool wait_ready(void) {
    uint32_t start=millis();
    while (!vs_ready()) if ((uint32_t)(millis()-start)>500) return false;
    return true;
}
static bool reg_write(uint8_t reg,uint16_t value) {
    uint8_t rx;
    if (!wait_ready()) return false;
    vs_select(false,true);
    bool ok=vs_byte(2,&rx) && vs_byte(reg,&rx) && vs_byte(value>>8,&rx) && vs_byte(value&255,&rx);
    vs_select(false,false);
    // DREQ may drop after the final SCI clock; allow the specified settling time.
    delay_ms(1);
    return ok && wait_ready();
}
static bool reg_read(uint8_t reg,uint16_t *value) {
    uint8_t rx,hi=0,lo=0;
    if (!wait_ready()) return false;
    vs_select(false,true);
    bool ok=vs_byte(3,&rx) && vs_byte(reg,&rx) && vs_byte(0xff,&hi) && vs_byte(0xff,&lo);
    vs_select(false,false); delay_ms(1);
    *value=((uint16_t)hi<<8)|lo;
    return ok && wait_ready();
}
bool decoder_volume(uint8_t attenuation) {
    return reg_write(0x0b,((uint16_t)attenuation<<8)|attenuation);
}
void decoder_off(void) {
    vs_select(false,false); vs_select(true,false); vs_reset(true);
}
bool decoder_init(uint8_t attenuation) {
    decoder_off(); vs_speed(false); delay_ms(5); vs_reset(false); delay_ms(5);
    uint16_t status;
    if (!reg_read(1,&status) || ((status>>4)&15)!=3) return false;
    // Native separate SCI/SDI selects. 3x clock + up to 1x automatic addition.
    if (!reg_write(0,0x0800) || !reg_write(3,0x9000) || !reg_write(2,0)) return false;
    vs_speed(true);
    return decoder_volume(attenuation);
}
bool decoder_send(const uint8_t *bytes,unsigned count) {
    if (count>32 || !vs_ready()) return false;
    uint8_t rx;
    vs_select(true,true);
    for (unsigned i=0;i<count;i++) {
        if (!vs_byte(bytes[i],&rx)) { vs_select(true,false); return false; }
    }
    vs_select(true,false); return true;
}