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;
}