56#include <linux/i2c-dev.h>
67#define SAMPLE_RATE 44100
70#define LOG_DOMAIN "audio"
83 pynq_error(
"audio_select_input: invalid input %d, must be LINE_IN or MIC\n",
92 unsigned char u8TxData[3];
94 u8TxData[1] = u8RegAddr;
97 pynq_error(
"write_audio_reg: unable to write audio register, ensure sudo "
98 "chmod 666 /dev/i2c-1 has been executed. \n");
104 unsigned char u8TxData[8], u8RxData[6];
108 pynq_error(
"config_audio_pll: unable to set I2C %d\n", iic_index);
140 pynq_error(
"config_audio_pll: unable to write audio register, ensure sudo "
141 "chmod 666 /dev/i2c-1 has been executed. \n");
149 pynq_error(
"writeI2C_asFile: unable to write audio register, ensure sudo "
150 "chmod 666 /dev/i2c-1 has been executed. \n");
153 pynq_error(
"readI2C_asFile: unable to write audio register, ensure sudo "
154 "chmod 666 /dev/i2c-1 has been executed. \n");
156 }
while ((u8RxData[5] & 0x02) == 0);
165 pynq_error(
"config_audio_pll: unable to set I2C %d\n", iic_fd);
179 pynq_error(
"config_audio_codec: unable to set I2C %d\n", iic_index);
230 pynq_error(
"config_audio_codec: unable to unset I2C %d\n", iic_index);
239 pynq_error(
"select_line_in: unable to set I2C %d\n", iic_index);
253 pynq_error(
"select_line_in: unable to unset I2C %d\n", iic_index);
262 pynq_error(
"select_mic: unable to set I2C %d, ensure sudo chmod 666 "
263 "/dev/i2c-1 has been executed\n",
282 pynq_error(
"select_mic: unable to unset I2C %d\n", iic_index);
291 pynq_error(
"deselect: unable to set I2C %d\n", iic_index);
300 pynq_error(
"deselect: unable to unset I2C %d\n", iic_index);
305 unsigned int volume,
int uio_index) {
307 pynq_error(
"audio_bypass: uio_index outside of range. is %d, should be "
312 pynq_error(
"audio_bypass: volume outside allowed range. Is %d, should be "
323 uio_ptr =
setUIO(uio_index, audio_mmap_size);
326 pynq_error(
"audio_bypass: unable to set I2C %d, ensure sudo chmod 666 "
327 "/dev/i2c-1 has been executed\n",
338 unsigned char vol_register = (
unsigned char)volume << 2 | 0x3;
345 for (
unsigned int i = 0; i < nsamples; i++) {
348 status = *((
volatile unsigned *)(((uint8_t *)uio_ptr) +
I2S_STATUS_REG));
349 }
while (status == 0);
369 if (
unsetUIO(uio_ptr, audio_mmap_size) < 0) {
370 pynq_error(
"audio_bypass: unable to free UIO %d, ensure sudo chmod 666 "
371 "/dev/i2c-1 has been executed\n",
375 pynq_error(
"audio_bypass: unable to unset I2C %d, ensure sudo chmod 666 "
376 "/dev/i2c-1 has been executed\n",
382 unsigned int nsamples,
int uio_index) {
384 pynq_error(
"audio_record: uio_index outside of range. is %d, should be "
389 unsigned int i, status;
394 uio_ptr =
setUIO(uio_index, audio_mmap_size);
397 pynq_error(
"audio_record: unable to set I2C %d, ensure sudo chmod 666 "
398 "/dev/i2c-1 has been executed\n",
402 for (i = 0; i < nsamples; i++) {
404 status = *((
volatile unsigned *)(((uint8_t *)uio_ptr) +
I2S_STATUS_REG));
405 }
while (status == 0);
414 *(BufAddr + 2 * i) = DataL;
415 *(BufAddr + 2 * i + 1) = DataR;
418 if (
unsetUIO(uio_ptr, audio_mmap_size) < 0) {
419 pynq_error(
"audio_record: unable to free UIO %d, ensure sudo chmod 666 "
420 "/dev/i2c-1 has been executed\n",
424 pynq_error(
"audio_record: unable to unset I2C %d, ensure sudo chmod 666 "
425 "/dev/i2c-1 has been executed\n",
430void audio_play(
unsigned int audio_mmap_size,
unsigned int *BufAddr,
431 unsigned int nsamples,
unsigned int volume,
int uio_index) {
434 "audio_play: uio_index outside of range. is %d, should be below 3. \n",
438 pynq_error(
"audio_play: volume outside allowed range. Is %d, should be "
443 unsigned int i, status;
448 uio_ptr =
setUIO(uio_index, audio_mmap_size);
451 pynq_error(
"audio_play: unable to set I2C %d, ensure sudo chmod 666 "
452 "/dev/i2c-1 has been executed\n",
460 unsigned char vol_register = (
unsigned char)volume << 2 | 0x3;
467 for (i = 0; i < nsamples; i++) {
469 status = *((
volatile unsigned *)(((uint8_t *)uio_ptr) +
I2S_STATUS_REG));
470 }
while (status == 0);
475 DataL = *(BufAddr + 2 * i);
476 DataR = *(BufAddr + 2 * i + 1);
490 if (
unsetUIO(uio_ptr, audio_mmap_size) < 0) {
491 pynq_error(
"audio_play: unable to free UIO %d, ensure sudo chmod 666 "
492 "/dev/i2c-1 has been executed\n",
496 pynq_error(
"audio_play: unable to unset I2C %d, ensure sudo chmod 666 "
497 "/dev/i2c-1 has been executed\n",
503 unsigned int nsamples,
unsigned int volume,
504 unsigned int repetitions) {
506 pynq_error(
"audio_repeat_play: volume outside allowed range. Is %d, should "
511 unsigned int i, status;
516 uio_ptr =
setUIO(0, audio_mmap_size);
519 pynq_error(
"audio_repeat_play: unable to set I2C %d, ensure sudo chmod 666 "
520 "/dev/i2c-1 has been executed\n",
528 unsigned char vol_register = (
unsigned char)volume << 2 | 0x3;
535 for (
unsigned int repeat = 0; repeat < repetitions; repeat++) {
536 for (i = 0; i < nsamples; i++) {
540 }
while (status == 0);
545 DataL = *(BufAddr + 2 * i);
546 DataR = *(BufAddr + 2 * i + 1);
560 if (
unsetUIO(uio_ptr, audio_mmap_size) < 0) {
561 pynq_error(
"audio_repeat_play: unable to free UIO %d\n", 0);
564 pynq_error(
"audio_repeat_play: unable to unset I2C %d, ensure sudo chmod "
565 "666 /dev/i2c-1 has been executed\n",
571 unsigned int volume) {
573 if (frequency < 10) {
574 pynq_error(
"audio_generate_tone: frequency should be 10 or higher, "
575 "frequency is: %d\n",
579 pynq_error(
"audio_generate_tone: volume outside allowed range. Is %d, "
580 "should be below 100 \n",
583 double period = 1 / ((double)(frequency));
584 unsigned int samplesPerPeriod = (int)(
SAMPLE_RATE * period);
585 double time_s = ((double)(time_ms)) / 1000;
586 int totalPeriods = (int)(time_s / period);
589 uint32_t audioBuffer[16 * 1024 + 1] = {0};
590 unsigned int i, status;
592 for (i = 0; i < samplesPerPeriod; i++) {
594 double value = sin(6.28318531 * frequency * t);
596 value = value * 16000;
597 audioBuffer[2 * i] = (uint32_t)value;
598 audioBuffer[2 * i + 1] = (uint32_t)value;
601 unsigned int audio_mmap_size = 64 * 1024;
602 unsigned int *BufAddr = audioBuffer;
608 uio_ptr =
setUIO(0, audio_mmap_size);
611 pynq_error(
"audio_generate_tone: unable to set I2C %d, ensure sudo chmod "
612 "666 /dev/i2c-1 has been executed\n",
620 unsigned char vol_register = (
unsigned char)volume << 2 | 0x3;
627 for (
int period = 0; period < totalPeriods; period++) {
628 for (i = 0; i < samplesPerPeriod; i++) {
632 }
while (status == 0);
637 DataL = *(BufAddr + 2 * i);
638 DataR = *(BufAddr + 2 * i + 1);
652 if (
unsetUIO(uio_ptr, audio_mmap_size) < 0) {
653 pynq_error(
"audio_generate_tone: unable to free UIO %d, ensure sudo chmod "
654 "666 /dev/i2c-1 has been executed\n",
658 pynq_error(
"audio_generate_tone: unable to unset I2C %d, ensure has been "
int setI2C(unsigned int index, long slave_addr)
int writeI2C_asFile(int i2c_fd, unsigned char writebuffer[], unsigned char bytes)
int readI2C_asFile(int i2c_fd, unsigned char readbuffer[], unsigned char bytes)
void * setUIO(int uio_index, int length)
int unsetUIO(void *uio_ptr, int length)
void audio_generate_tone(unsigned int frequency, uint32_t time_ms, unsigned int volume)
void deselect(void)
Function to deselect input, either LINE_IN, or MIC.
void audio_record(unsigned int audio_mmap_size, unsigned int *BufAddr, unsigned int nsamples, int uio_index)
Function to support audio recording without the audio codec controller.
void select_mic(void)
Function to select MIC as input.
void write_audio_reg(unsigned char u8RegAddr, unsigned char u8Data, int iic_fd)
void audio_repeat_play(unsigned int audio_mmap_size, unsigned int *BufAddr, unsigned int nsamples, unsigned int volume, unsigned int repetitions)
Function to play one audio fragment for multiple repititions.
void config_audio_codec(void)
void audio_play(unsigned int audio_mmap_size, unsigned int *BufAddr, unsigned int nsamples, unsigned int volume, int uio_index)
void audio_bypass(unsigned int audio_mmap_size, unsigned int nsamples, unsigned int volume, int uio_index)
Record and play the audio without storing in DRAM.
void audio_select_input(int input)
selects the audio input channel.
#define I2S_DATA_RX_R_REG
void audio_init(void)
Initializes the audio register. Sets the sampling frequency. defines several values such as audio rec...
#define I2S_DATA_TX_R_REG
void config_audio_pll(void)
#define I2S_DATA_RX_L_REG
#define I2S_DATA_TX_L_REG
void select_line_in(void)
Function to select LINE_IN as input.
@ R8_LEFT_DIFFERENTIAL_INPUT_VOLUME_CONTROL
@ R9_RIGHT_DIFFERENTIAL_INPUT_VOLUME_CONTROL
@ R29_PLAYBACK_HEADPHONE_LEFT_VOLUME_CONTROL
@ R5_RECORD_MIXER_LEFT_CONTROL_1
@ R22_PLAYBACK_MIXER_LEFT_CONTROL_0
@ R6_RECORD_MIXER_RIGHT_CONTROL_0
@ R35_PLAYBACK_POWER_MANAGEMENT
@ R30_PLAYBACK_HEADPHONE_RIGHT_VOLUME_CONTROL
@ R58_SERIAL_INPUT_ROUTE_CONTROL
@ R59_SERIAL_OUTPUT_ROUTE_CONTROL
@ R23_PLAYBACK_MIXER_LEFT_CONTROL_1
@ R7_RECORD_MIXER_RIGHT_CONTROL_1
@ R4_RECORD_MIXER_LEFT_CONTROL_0
@ R24_PLAYBACK_MIXER_RIGHT_CONTROL_0
@ R10_RECORD_MICROPHONE_BIAS_CONTROL
@ R15_SERIAL_PORT_CONTROL_0
@ R25_PLAYBACK_MIXER_RIGHT_CONTROL_1