Atsushi Shinbo / Mbed 2 deprecated CS8416_SPI

Dependencies:   mbed

main.cpp

Committer:
shinbo
Date:
2014-05-04
Revision:
1:f468352a5408
Parent:
0:cb6ecbfcf585
Child:
2:849b0ab61874

File content as of revision 1:f468352a5408:

#include "mbed.h"

// this program control CS8416 in software mode(SPI) with LPC1114FN28.

// CS8416 : 192 kHz Digital Audio Interface Receiver
// http://www.cirrus.com/jp/pubs/proDatasheet/CS8416_F3.pdf

// FN1242A : 24bit/192KHz/2ch DAC
// http://akizukidenshi.com/download/ds/niigataseimitsu/FN1242Ajspec.pdf


// LPC1114FN28      connect to
//  1  MISO         cs8416 / CDOUT
//  2  MOSI         cs8416 / CDIN
//  3  SWCLK        LPC-Link
//  4  PIO          cs8416 / CS
//  6  SCK          cs8416 / CCLK
//  7  AVIN 3.3V
//  8  AGND
//  9  PIO          toggle switch : input source select.
// 12  SWDIO        LPC-Link
// 14  PIO          cs8416 / reset
// 15  PIO          led1 : left
// 16  PIO          led2 
// 17  PIO          led3
// 18  PIO          led4 : right
// 21  VIN 3.3V
// 22  GND
// 23  RESET        LPC-Link
// 24  PIO          fn1242a / ML
// 25  PIO          fn1242a / MD
// 26  PIO          fn1242a / MC

// CS8416
// RXP0 : S/PDIF TOSLINK input
// RXP1 : S/PDIF COAX input
// OMCK : 11.2896 MHz

SPI        spi(dp2, dp1, dp6);      // mosi, miso, sclk
DigitalOut pin_cs  (dp4);
DigitalOut pin_rst (dp14);
DigitalOut pin_led1(dp15);
DigitalOut pin_led2(dp16);
DigitalOut pin_led3(dp17);
DigitalOut pin_led4(dp18);
DigitalIn  pin_tgl (dp9);
DigitalOut pin_ML  (dp24);
DigitalOut pin_MD  (dp25);
DigitalOut pin_MC  (dp26);


const uint8_t DEF_REGVAL[10] = {
    0x04,   // [0] Control0                  
    // TRUNC=1 - Incoming data is truncated according to the length specified in the channel status data.
    
    0x80,   // [1] Control1                  
    // SWCLK=1 - Enable automatic clock switching on PLL unlock. OMCK clock input is automatically output on RMCK on PLL Unlock.
    // MUTESAO=0 - SDOUT not muted.
    // HOLD[1:0]=00 - hold last audio sample.
    
    0x45,   // [2] Control2                  
    // EMPH_CNTL[2:0]=100 - deemphasis filter auto select.
    // GPO0SEL[3:0]=0101 - RERR/Receiver Error

    0x00,   // [3] Control3

    0x80,   // [4] Control4                  
    // RUN=1 - normal part operation

    0x85,   // [5] Serial Audio Data Format
    // SOMS=1 - Serial audio output port is in master mode. OSCLK and OLRCK are outputs.
    // SOSF=0 - OSCLK output frequency is 64*Fs.
    // SORES[1:0]=00 - 24-bit resolution.
    // SOJUST=0 - Left-Justified.
    // SODEL=1 - second OSCLK period.
    // SOSPOL=0 - SDOUT is sampled on rising edges of OSCLK.
    // SOLRPOL=1 - right channel when OLRCK is high.
    
    0x00,   // 0x06 : Receiver Error Mask
    0x00,   // 0x07 : Interrupt Mask
    0x00,   // 0x08 : Interrupt Mode MSB
    0x00    // 0x09 : Interrupt Mode LSB
};

uint32_t g_freq = 0;
uint8_t  g_cur_frmt = 0;
uint32_t g_cur_tgl = 0;


void fn1242_write(uint16_t word) {
    
    pin_ML = 1;
    
    for (int iii = 0; iii < 16; iii++) {
        pin_MC = 0;
        pin_MD = (word & 0x8000) == 0 ? 0 : 1;      // msb first
        wait_us(10);            // us
        
        pin_MC = 1;
        wait_us(10);            // us
        
        word = word << 1;
    }
    
    pin_MD = 0;
    pin_MC = 0;
    pin_ML = 0;
    wait_us(10);                // us
    
    pin_ML = 1;
    wait_us(10);                // us
}

void fn1242_init() {
    
    pin_ML = 1;
    pin_MD = 0;
    pin_MC = 0;
    wait_us(10);                // us
    
    fn1242_write(
              (2 << 11)     // MODE2
            | (0 <<  9)     // OM  (default)
            | (0 <<  8)     // RST (OFF/default)
            | (2 <<  6)     // BIT (24bit)
            | (0 <<  4)     // ZM  (default)
            | (0 <<  3)     // ATC (default)
            | (0 <<  2)     // MUTE (OFF/default)
            | (0      ) );  // EMPH (OFF/default)

    wait_us(10);                // us
    fn1242_write(
              (0 << 11)     // MODE0
            | (0 << 10)     // LDL -> disable
            |  1023);       // 10bit
    wait_us(10);                // us
    fn1242_write(
              (1 << 11)     // MODE1
            | (0 << 10)     // LDR -> disable
            |  1023);       // 10bit

}

void cs8416_write(uint8_t u8_addr, uint8_t u8_data) {
    uint8_t u8_recv = 0;
    
    pin_cs = 0;
    wait_us(10);                    // us
    u8_recv = spi.write(0x20);
    u8_recv = spi.write(u8_addr);
    u8_recv = spi.write(u8_data);
    pin_cs = 1;
    wait_us(10);                    // us
}


uint8_t cs8416_read(uint8_t u8_addr) {
    uint8_t u8_recv = 0;
    
    pin_cs = 0;
    wait_us(10);                    // us
    u8_recv = spi.write(0x20);
    u8_recv = spi.write(u8_addr);
    pin_cs = 1;
    wait_us(10);                    // us
    
    pin_cs = 0;
    wait_us(10);                    // us
    u8_recv = spi.write(0x21);
    u8_recv = spi.write(0x00);
    pin_cs = 1;
    wait_us(10);                    // us
    
    return u8_recv;
}


void cs8416_init() {
    
    pin_rst = 0;                    // reset
    wait_ms(100);                   // ms
    pin_rst = 1;
    wait_ms(1);                     // ms
    
    // SPI Mode is selected if there is a high to low transition on the AD0/CS pin, after the RST pin has been brought high.
    pin_cs = 1; wait_ms(1);     
    pin_cs = 0; wait_ms(1);         // enter SPI mode
    pin_cs = 1; wait_ms(1);
    
    for (int iii = 0; iii < 10; iii++) {
        uint8_t u8_addr = (uint8_t) iii;
        uint8_t u8_data = DEF_REGVAL[iii];
        cs8416_write(u8_addr, u8_data);
    }
}


void decide_freq(uint8_t u8_addr18) {
       
    switch (u8_addr18) {
        case 0x59:
        case 0x58:
        case 0x57:  g_freq =  32; break;
        
        case 0x40:
        case 0x3f:  g_freq =  44; break;
        
        case 0x3b:
        case 0x3a:  g_freq =  48; break;
        
        case 0x20:
        case 0x1f:  g_freq =  88; break;
        
        case 0x1d:
        case 0x1c:  g_freq =  96; break;
        
        case 0x10:
        case 0x0f:  g_freq = 176; break;
        
        case 0x0e:  g_freq = 192; break;
        
        default:    g_freq =   0; break;
    }
}


void set_led() {
    uint32_t u32_val = 0;
    
    switch (g_freq) {
        case  32: u32_val = 0x01; break;     // 0001
        case  44: u32_val = 0x02; break;     // 0010
        case  48: u32_val = 0x03; break;     // 0011
        case  88: u32_val = 0x04; break;     // 0100
        case  96: u32_val = 0x05; break;     // 0101
        case 176: u32_val = 0x06; break;     // 0110
        case 192: u32_val = 0x07; break;     // 0111
    }
    
    pin_led4 = (u32_val & 1); u32_val = u32_val >> 1;
    pin_led3 = (u32_val & 1); u32_val = u32_val >> 1;
    pin_led2 = (u32_val & 1); u32_val = u32_val >> 1;
}


void set_rmckf() {
    uint8_t u8_data = 0;
    
    if (g_cur_frmt & 1) {           // (0Bh)[0] 96KHZ - If the input sample rate is <= 48 kHz, outputs a "0". Outputs a "1" if the sample rate is >= 88.1 kHz. Otherwise the output is indeterminate.
        pin_led1 = 1;
        u8_data = 0x02;             // (01h)[1] RMCKF - Recovered Master Clock Frequency @ 1 : 128 Fs
    } else {
        pin_led1 = 0;
        u8_data = 0x00;             // (01h)[1] RMCKF - Recovered Master Clock Frequency @ 0 : 256 Fs
    }
    
    if (g_freq == 0) {
        u8_data |= 0x40;             // (01h)[6] MUTESAO - Mute control for the serial audio output port
    }
    cs8416_write(0x01, DEF_REGVAL[1] | u8_data);    // (01h) : Control1
}


void set_source() {
    uint8_t u8_data = 0;
    
    if (g_cur_tgl & 1) {
        u8_data = 0x08;             // (04h)[5:3] RXSEL2:0
    } else {
        u8_data = 0x00;             // (04h)[5:3] RXSEL2:0
    }
    cs8416_write(0x04, DEF_REGVAL[4] | u8_data);    // (04h) : Control4
}


int main() {
    
    spi.format(8, 3);               // 8bit, mode3
    spi.frequency(1000000);         // 1MHz : default
    
    cs8416_init();
    fn1242_init();
    
    while (1) {
        uint32_t u32_freq = g_freq;
        
        uint8_t u8_addr18 = cs8416_read(0x18);  // (18h) : OMCK/RMCK Ratio
        decide_freq(u8_addr18);
        set_led();
        
        uint8_t u8_addr0B = cs8416_read(0x0b);  // (0Bh) : Format Detect Status
        if ((g_cur_frmt != u8_addr0B) || (g_freq != u32_freq)) {
            g_cur_frmt = u8_addr0B;
            set_rmckf();
        }
        
        uint32_t u32_tgl = pin_tgl;
        if (g_cur_tgl != u32_tgl) {
            g_cur_tgl = u32_tgl;
            set_source();
        }
        
        wait_ms(200);               // ms
    }

}