Forum Discussion

wlin25's avatar
wlin25
Icon for New Contributor rankNew Contributor
7 years ago

Need help to configure the audio CODEC (WM8731) on DE1-SoC board through the HPS

Hello,

Sorry for my English, I will try my best to describe my problem.

I was struggling to configure the audio CODEC (WM8731) for a few months and still not figure out the problem :(

So the intention is that I have to configure the audio CODEC

through the HPS, after that using the audio core in Qsys to get the data from the audio chip.

I cannot use NIOS and any OS like Linux.

At very first step, the audio CODEC should be configured before using the audio core, and I face the problem.

I was making the Qsys project with audio core base on the GHRD.

I created the C project in ARM DS-5.

Follow the datasheet, in order to make the HPS access to the audio CODED, the signal of HPS_I2C_CONTROL need to set high.

After that, I used the HWlib that provide with EDS to implement

the I2C communication between the HPS I2C controller and audio CODEC.

However, when I run the debugger, feed the audio from line-in and connect line-out with speaker, no sound appear.

I couldn't figure out what is the problem.

Does anyone can help me?

//the function to set up the HPS_I2C_CONTROL and HPS_LED GPIO
void setup_hps_gpio() {
	uint32_t hps_gpio_config_len = 2;
    ALT_GPIO_CONFIG_RECORD_t hps_gpio_config[] ={
    	{HPS_LED_IDX  , ALT_GPIO_PIN_OUTPUT, 0, 0, ALT_GPIO_PIN_DEBOUNCE, ALT_GPIO_PIN_DATAZERO},
    	{HPS_I2C_CONTROL_IDX, ALT_GPIO_PIN_OUTPUT, 0, 0, ALT_GPIO_PIN_DEBOUNCE, ALT_GPIO_PIN_DATAZERO}
    };
 
    assert(ALT_E_SUCCESS == alt_gpio_init());
    assert(ALT_E_SUCCESS == alt_gpio_group_config(hps_gpio_config, hps_gpio_config_len));
}
 
void setup_hps_timer() {
    assert(ALT_E_SUCCESS == alt_globaltmr_init());
}
 
//delay function
void delay_us(uint32_t us)
{
    uint64_t start_time = alt_globaltmr_get64();
    uint32_t timer_prescaler = alt_globaltmr_prescaler_get() + 1;
    uint64_t end_time;
    alt_freq_t timer_clock;
 
    alt_clk_freq_get(ALT_CLK_MPU_PERIPH, &timer_clock);
    end_time = start_time + us * ((timer_clock / timer_prescaler) / 1000000);
 
    while(alt_globaltmr_get64() < end_time)
    {
    }
}
 
//The function control the HPS_I2C_CONTORL signal high or low
void handle_hps_i2c_control(bool hps_i2c_ctrl_sw) {
	if(hps_i2c_ctrl_sw){
 
		// get the value from the GPIO1 register
        uint32_t hps_value = alt_read_word(ALT_GPIO1_SWPORTA_DR_ADDR);
 
		// set the hps_value = 0x0
		hps_value = ALT_GPIO_SWPORTA_DR_GPIO_SWPORTA_DR_RESET;
 
		// set the hps_value to be 0x1fffffff
        hps_value = hps_value | ALT_GPIO_SWPORTA_DR_GPIO_SWPORTA_DR_SET_MSK;
 
		// turn on HPS_LED
        assert(ALT_E_SUCCESS == alt_gpio_port_data_write(HPS_LED_PORT, HPS_LED_MASK, hps_value));
 
		// set HPS_I2C_CONTROL to high
		assert(ALT_E_SUCCESS == alt_gpio_port_data_write(HPS_I2C_CONTROL_PORT, HPS_I2C_CONTROL_MASK, hps_value));
	}
 
	if(hps_i2c_ctrl_sw == false){
 
		uint32_t hps_value = alt_read_word(ALT_GPIO1_SWPORTA_DR_ADDR);
 
		// set the hps_value = 0x0
		hps_value = ALT_GPIO_SWPORTA_DR_GPIO_SWPORTA_DR_RESET;
 
		// turn off HPS_LED
        assert(ALT_E_SUCCESS == alt_gpio_port_data_write(HPS_LED_PORT, HPS_LED_MASK, hps_value));
 
		// set HPS_I2C_CONTROL to low
		assert(ALT_E_SUCCESS == alt_gpio_port_data_write(HPS_I2C_CONTROL_PORT, HPS_I2C_CONTROL_MASK, hps_value));
	}
}
 
static ALT_STATUS_CODE i2c_init(ALT_I2C_DEV_t* device)
{
    ALT_STATUS_CODE status = ALT_E_SUCCESS;
    ALT_I2C_MASTER_CONFIG_t cfg;
    uint32_t speed;
 
    // Init I2C module
    if (status == ALT_E_SUCCESS)
    {
        printf("INFO: Init I2C module.\n");
        status = alt_i2c_init(ALT_I2C_I2C0, device);
    }
 
    // Enable I2C module
    if (status == ALT_E_SUCCESS)
    {
        printf("INFO: Enable I2C module.\n");
		status = alt_i2c_enable(device);
    }
 
    // Configure I2C module
    printf("INFO: Configuring I2C parameters.\n");
 
    if (status == ALT_E_SUCCESS)
    {
        status = alt_i2c_master_config_get(device, &cfg);
    }
 
    if (status == ALT_E_SUCCESS)
    {
        status = alt_i2c_master_config_speed_set(device, &cfg, AUDIO_I2C_SPEED);
    }
 
    if (status == ALT_E_SUCCESS)
    {
        status = alt_i2c_master_config_speed_get(device, &cfg, &speed);
        printf("INFO: New I2C speed = %d Hz.\n", (int)speed);
    }
 
    if(status == ALT_E_SUCCESS)
    {
        cfg.addr_mode = ALT_I2C_ADDR_MODE_7_BIT;  // 7-bit format for the I2C address
		cfg.restart_enable = ALT_E_TRUE;
		cfg.fs_spklen = 2;
 
        status = alt_i2c_master_config_set(device, &cfg);
    }
 
    return status;
}
 
bool i2c_write(ALT_I2C_DEV_t * device, uint8_t controlAddr, uint8_t controlData){
 
	ALT_STATUS_CODE status = ALT_E_SUCCESS;
 
	if(status == ALT_E_SUCCESS){
 
		uint8_t send_buffer[2];
		const size_t send_size = 2;
 
		send_buffer[0] = controlAddr;
		send_buffer[1] = controlData;
 
        // Send the data to the device
        status = alt_i2c_master_transmit(device, send_buffer, send_size, ALT_E_FALSE, ALT_E_TRUE);
    } 
	printf("status = %d \r\n", status);
    return ALT_E_SUCCESS;
}
 
//This function is internal function used to initialise the audio codec
 
bool aduio_RegWrite(ALT_I2C_DEV_t * device, uint8_t reg_index, uint16_t data16){
    bool bSuccess;
 
    uint8_t ctrlData, ctrlRegAddr;
 
    if (reg_index <= 10)
        reg_file[reg_index] = data16;
 
    ctrlData = data16 & 0xFF;
 
    ctrlRegAddr = (reg_index << 1) & 0xFE;
    ctrlRegAddr |= ((data16 >> 8) & 0x01);
 
    printf("[AUDIO] set audio reg[%02d] = %04Xh\r\n", reg_index, data16);
 
    printf("I2C_AUDIO_ADDR = 0x%x, ctrlRegAddr = 0x%x, ctrlData = 0x%x\r\n",I2C_AUDIO_ADDR, ctrlRegAddr, ctrlData);
    bSuccess = i2c_write(device, ctrlRegAddr, ctrlData);
 
    printf("bSuccess = %d\r\n", bSuccess);
 
    if (bSuccess != ALT_E_SUCCESS)
        printf("[AUDIO] write reg fail!!!!\r\n");
    return bSuccess;
}
 
//The function to configure the audio codec
bool audio_config(ALT_I2C_DEV_t * device){
 
	ALT_STATUS_CODE bSuccess = ALT_E_SUCCESS;
 
    printf("[AUDIO] AUDIO_Init...\r\n");
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 15, 0x0000);  // reset
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 9, 0x0000);  // inactive interface
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 0, 0x0017);  // Left Line In: set left line in volume
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 1, 0x0017);  // Right Line In: set right line in volume
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 2, 0x005B);  // Left Headphone Out: set left line out volume
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 3, 0x005B);  // Right Headphone Out: set right line out volume
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 4, 0x001A);  // Analogue Audio Path Control: set line in ad input, and enable dac
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 5, 0x0000);  // Digital Audio Path Control: disable soft mute
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 6, 0x0000);  // power down control: power on all
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 7, 0x0041);  // left justied, iwl=16-bits, Enable slave Mode
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 8, 0x0002);  // Normal, Base Over-Sampleing Rate 384 fs (BOSR=1)
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS){
        bSuccess = aduio_RegWrite(device, 9, 0x0001);  // active interface
    	delay_us(1000);}
 
    if (bSuccess == ALT_E_SUCCESS)
    	printf("[AUDIO] AUDIO_Init success\r\n");
    else printf("[AUDIO] AUDIO_Init fail\r\n");
 
    return bSuccess;
}
 
int main(){
 
	ALT_I2C_DEV_t device;
	bool bRecordPress, bPlayPress;
 
	printf("DE1-SoC bare-metal - audio\n");
	setup_hps_timer();
 
	// set up the HPS_I2C_CONTROL and HPS_LED GPIO
	setup_hps_gpio();
 
	//  turn on the HPS_LED and set the HPS_I2C_CONTROL to high so HPS can access audio codec
	handle_hps_i2c_control(1);
 
	// initialise the i2c controller device to audio
	i2c_init(&device);
 
	// configure the audio codec
	audio_config(&device);
	return 0;
}

2 Replies

  • wlin25's avatar
    wlin25
    Icon for New Contributor rankNew Contributor

    Hello Sir,

    Thank you for your kindly reply.

    Yes, I look that video already and it gave me the general idea how to configure the audio CODEC at beginning.

    However, the language that the video used is VHDL and he used FPGA to initialize the chip.

    But I have to use the HPS to control the audio CODEC so it doesn't help after.

    For the example from github, I look at it before and I couldn't get any information from it since it's really different than the application without OS and using the HWlib (And I have never used linux before so it's even harder for me to completely understand the code) :(