Hello,
I would like to have an interrupt per sample of the SSC. I took the demo code from
https://microchipdeveloper.com/asf:audio-sine-tone-intro#Steps_anchor
and added ISR Handlers for SSC and XDMA to increment counter global variables. In the watch, I see the global counter go up only for the SSC Handler. How come the codec stops producing a waveform when I this in the code? How do I fix it?
NVIC_EnableIRQ(SSC_IRQn); ssc_enable_interrupt(SSC, 0xFFFFFFFF);
volatile uint32_t xdmacHandlerCount = 0; volatile uint32_t sscHandlerCount = 0; void XDMAC_Handler(void){ xdmacHandlerCount ++; } void SSC_Handler ( void ){ sscHandlerCount ++; }
Where do I find a quick start guide for SSC? I don't see anything here:
https://asf.microchip.com/docs/latest/get_started.html
The whole code is here:
Thanks,
Frank
#include <asf.h> /// @cond 0 /**INDENT-OFF**/ #ifdef __cplusplus extern "C" { #endif /**INDENT-ON**/ /// @endcond #define STRING_EOL "\r" #define STRING_HEADER "-- Audio sine tone using SSC on WM8904 --\r\n" \ "-- "BOARD_NAME" --\r\n" \ "-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL //#define PCK2 PMC_MCKR_CSS_MAIN_CLK #define PCK2 PMC_MCKR_CSS_SLOW_CLK /** Features of the stored sine tone */ /** Sampling rate */ #define SAMPLE_RATE (48000) /** slot per sample */ #define SLOT_BY_FRAME (2) /** Bits per slot */ #define BITS_BY_SLOT (16) /* Input Master Clock to SSC peripheral */ #define INPUT_MCK_TO_SSC 120000000 /** XDMA channel used in this example. */ #define XDMA_CH_SSC_TX 0 /** XDMA Descriptor */ #define TOTAL_BUFFERS 2 #define MAX_DMA_SIZE 240 static lld_view1 linklist_write[TOTAL_BUFFERS]; static uint16_t AudioBuffer[MAX_DMA_SIZE*(BITS_BY_SLOT / 8)]= { 0, 0, 1714, 1714, 3425, 3425, 5125, 5125, 6812, 6812, 8480, 8480, 10125, 10125, 11742, 11742, 13327, 13327, 14876, 14876, 16383, 16383, 17846, 17846, 19260, 19260, 20621, 20621, 21925, 21925, 23170, 23170, 24350, 24350, 25465, 25465, 26509, 26509, 27481, 27481, 28377, 28377, 29196, 29196, 29934, 29934, 30591, 30591, 31163, 31163, 31650, 31650, 32051, 32051, 32364, 32364, 32587, 32587, 32722, 32722, 32767, 32767, 32722, 32722, 32587, 32587, 32364, 32364, 32051, 32051, 31650, 31650, 31163, 31163, 30591, 30591, 29934, 29934, 29196, 29196, 28377, 28377, 27481, 27481, 26509, 26509, 25465, 25465, 24350, 24350, 23170, 23170, 21925, 21925, 20621, 20621, 19260, 19260, 17846, 17846, 16383, 16383, 14876, 14876, 13327, 13327, 11742, 11742, 10125, 10125, 8480, 8480, 6812, 6812, 5125, 5125, 3425, 3425, 1714, 1714, 0, 0, -1715, -1715, -3426, -3426, -5126, -5126, -6813, -6813, -8481, -8481, -10126, -10126, -11743, -11743, -13328, -13328, -14877, -14877, -16384, -16384, -17847, -17847, -19261, -19261, -20622, -20622, -21926, -21926, -23171, -23171, -24351, -24351, -25466, -25466, -26510, -26510, -27482, -27482, -28378, -28378, -29197, -29197, -29935, -29935, -30592, -30592, -31164, -31164, -31651, -31651, -32052, -32052, -32365, -32365, -32588, -32588, -32723, -32723, -32768, -32768, -32723, -32723, -32588, -32588, -32365, -32365, -32052, -32052, -31651, -31651, -31164, -31164, -30592, -30592, -29935, -29935, -29197, -29197, -28378, -28378, -27482, -27482, -26510, -26510, -25466, -25466, -24351, -24351, -23171, -23171, -21926, -21926, -20622, -20622, -19261, -19261, -17847, -17847, -16384, -16384, -14877, -14877, -13328, -13328, -11743, -11743, -10126, -10126, -8481, -8481, -6813, -6813, -5126, -5126, -3426, -3426, -1715, -1715 }; volatile uint32_t xdmacHandlerCount = 0; volatile uint32_t sscHandlerCount = 0; void XDMAC_Handler(void){ xdmacHandlerCount ++; } void SSC_Handler ( void ){ sscHandlerCount ++; } /** * \brief Configure UART console. */ static void configure_console(void) { const usart_serial_options_t uart_serial_options = { .baudrate = CONF_UART_BAUDRATE, .charlength = CONF_UART_CHAR_LENGTH, .paritytype = CONF_UART_PARITY, .stopbits = CONF_UART_STOP_BITS, }; /* Configure console UART. */ sysclk_enable_peripheral_clock(CONSOLE_UART_ID); stdio_serial_init(CONF_UART, &uart_serial_options); } /** * \brief Configure SSC in Master or Slave mode * (based on the value of macro PCK2) for Tx operation only */ static void configure_ssc(void) { clock_opt_t tx_clk_option; data_frame_opt_t tx_data_frame_option; /* Initialize clock */ pmc_enable_periph_clk(ID_SSC); /* Reset SSC */ ssc_reset(SSC); if(PCK2 == PMC_MCKR_CSS_SLOW_CLK) { /* Transmitter clock mode configuration. */ tx_clk_option.ul_cks = SSC_TCMR_CKS_TK; tx_clk_option.ul_cko = SSC_TCMR_CKO_NONE; tx_clk_option.ul_cki = 0; tx_clk_option.ul_ckg = SSC_TCMR_CKG_CONTINUOUS; tx_clk_option.ul_start_sel = SSC_TCMR_START_TF_EDGE; tx_clk_option.ul_sttdly = 1; tx_clk_option.ul_period = BITS_BY_SLOT - 1; /* Transmitter frame mode configuration. */ tx_data_frame_option.ul_datlen = BITS_BY_SLOT - 1; tx_data_frame_option.ul_msbf = SSC_TFMR_MSBF; tx_data_frame_option.ul_datnb = 0; tx_data_frame_option.ul_fslen = BITS_BY_SLOT - 1; tx_data_frame_option.ul_fslen_ext = 0; tx_data_frame_option.ul_fsos = SSC_TFMR_FSOS_NONE; tx_data_frame_option.ul_fsedge = SSC_TFMR_FSEDGE_POSITIVE; } else { ssc_set_clock_divider(SSC, ((BITS_BY_SLOT*SLOT_BY_FRAME)*SAMPLE_RATE), INPUT_MCK_TO_SSC); /* Transmitter clock mode configuration. */ tx_clk_option.ul_cks = SSC_TCMR_CKS_MCK; tx_clk_option.ul_cko = SSC_TCMR_CKO_CONTINUOUS; tx_clk_option.ul_cki = 0; tx_clk_option.ul_ckg = SSC_TCMR_CKG_CONTINUOUS; tx_clk_option.ul_start_sel = SSC_TCMR_START_TF_EDGE; tx_clk_option.ul_sttdly = 1; tx_clk_option.ul_period = BITS_BY_SLOT - 1; /* Transmitter frame mode configuration. */ //tx_data_frame_option.ul_datlen = BITS_BY_SLOT - 1; tx_data_frame_option.ul_datlen = BITS_BY_SLOT - 1; tx_data_frame_option.ul_msbf = SSC_TFMR_MSBF; tx_data_frame_option.ul_datnb = SLOT_BY_FRAME - 1; tx_data_frame_option.ul_fslen = BITS_BY_SLOT - 1; tx_data_frame_option.ul_fslen_ext = 0; tx_data_frame_option.ul_fsos = SSC_TFMR_FSOS_NEGATIVE; tx_data_frame_option.ul_fsedge = SSC_TFMR_FSEDGE_POSITIVE; } ssc_set_transmitter(SSC, &tx_clk_option, &tx_data_frame_option); /* Disable transmitter first */ ssc_disable_tx(SSC); /* Disable All Interrupt */ ssc_disable_interrupt(SSC, 0xFFFFFFFF); } /** * \brief Configure DMA */ static void configure_xdma(void) { uint16_t *src; uint8_t i; xdmac_channel_config_t xdmac_channel_cfg = {0}; /* Initialize and enable DMA controller */ pmc_enable_periph_clk(ID_XDMAC); xdmac_channel_cfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN | XDMAC_CC_MBSIZE_SINGLE | XDMAC_CC_DSYNC_MEM2PER | XDMAC_CC_CSIZE_CHK_1 | XDMAC_CC_DWIDTH_HALFWORD | XDMAC_CC_SIF_AHB_IF0 | XDMAC_CC_DIF_AHB_IF1 | XDMAC_CC_SAM_INCREMENTED_AM | XDMAC_CC_DAM_FIXED_AM | XDMAC_CC_PERID(32); xdmac_configure_transfer(XDMAC, XDMA_CH_SSC_TX, &xdmac_channel_cfg); src = &AudioBuffer[0]; for(i = 0; i < TOTAL_BUFFERS; i++) { linklist_write[i].mbr_ubc = XDMAC_UBC_NVIEW_NDV1 | XDMAC_UBC_NDE_FETCH_EN | XDMAC_UBC_NSEN_UPDATED | XDMAC_UBC_NDEN_UNCHANGED | XDMAC_CUBC_UBLEN(MAX_DMA_SIZE); linklist_write[i].mbr_sa = (uint32_t)(src); linklist_write[i].mbr_da = (uint32_t)&(SSC->SSC_THR); if ( i == (TOTAL_BUFFERS - 1 )) { linklist_write[i].mbr_nda = (uint32_t)&linklist_write[0]; } else { linklist_write[i].mbr_nda = (uint32_t)&linklist_write[i+1]; } } xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_SSC_TX, XDMAC_CNDC_NDVIEW_NDV1 | XDMAC_CNDC_NDE_DSCR_FETCH_EN | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED); xdmac_channel_set_descriptor_addr(XDMAC, XDMA_CH_SSC_TX, (uint32_t)(&linklist_write[0]), 0); xdmac_enable_interrupt(XDMAC, XDMA_CH_SSC_TX); xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_SSC_TX, XDMAC_CIE_LIE); /*Enable XDMA interrupt */ NVIC_ClearPendingIRQ(XDMAC_IRQn); NVIC_SetPriority(XDMAC_IRQn ,1); NVIC_EnableIRQ(XDMAC_IRQn); } /** * \brief Configure Codec WM8904 in Master or Slave mode * (based on the value of macro PCK2) for audio playback */ static void configure_codec(void) { uint16_t data = 0; /* check that WM8904 is present */ wm8904_write_register(WM8904_SW_RESET_AND_ID, 0xFFFF); data = wm8904_read_register(WM8904_SW_RESET_AND_ID); if(data != 0x8904) { printf("WM8904 not found!\n\r"); while(1); } if(PCK2 == PMC_MCKR_CSS_SLOW_CLK) { wm8904_write_register(WM8904_BIAS_CONTROL_0, WM8904_ISEL_HP_BIAS); wm8904_write_register(WM8904_VMID_CONTROL_0, WM8904_VMID_BUF_ENA | WM8904_VMID_RES_FAST | WM8904_VMID_ENA); delay_ms(5); wm8904_write_register(WM8904_VMID_CONTROL_0, WM8904_VMID_BUF_ENA | WM8904_VMID_RES_NORMAL | WM8904_VMID_ENA); wm8904_write_register(WM8904_BIAS_CONTROL_0, WM8904_ISEL_HP_BIAS | WM8904_BIAS_ENA); wm8904_write_register(WM8904_POWER_MANAGEMENT_0, WM8904_INL_ENA | WM8904_INR_ENA); wm8904_write_register(WM8904_POWER_MANAGEMENT_2, WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA); wm8904_write_register(WM8904_DAC_DIGITAL_1, WM8904_DEEMPH(0)); wm8904_write_register(WM8904_ANALOGUE_OUT12_ZC, 0x0000); wm8904_write_register(WM8904_CHARGE_PUMP_0, WM8904_CP_ENA); wm8904_write_register(WM8904_CLASS_W_0, WM8904_CP_DYN_PWR); wm8904_write_register(WM8904_FLL_CONTROL_1, 0x0000); wm8904_write_register(WM8904_FLL_CONTROL_2, WM8904_FLL_OUTDIV(7)| WM8904_FLL_FRATIO(4)); wm8904_write_register(WM8904_FLL_CONTROL_3, WM8904_FLL_K(0x8000)); wm8904_write_register(WM8904_FLL_CONTROL_4, WM8904_FLL_N(0xBB)); wm8904_write_register(WM8904_FLL_CONTROL_1, WM8904_FLL_FRACN_ENA | WM8904_FLL_ENA); delay_ms(5); wm8904_write_register(WM8904_CLOCK_RATES_1, WM8904_CLK_SYS_RATE(3) | WM8904_SAMPLE_RATE(5)); wm8904_write_register(WM8904_CLOCK_RATES_0, 0x0000); wm8904_write_register(WM8904_CLOCK_RATES_2, WM8904_SYSCLK_SRC | WM8904_CLK_SYS_ENA | WM8904_CLK_DSP_ENA); wm8904_write_register(WM8904_AUDIO_INTERFACE_1, WM8904_BCLK_DIR | WM8904_AIF_WL_16BIT | WM8904_AIF_FMT_I2S); wm8904_write_register(WM8904_AUDIO_INTERFACE_2, WM8904_BCLK_DIV(8)); wm8904_write_register(WM8904_AUDIO_INTERFACE_3, WM8904_LRCLK_DIR | WM8904_LRCLK_RATE(0x20)); wm8904_write_register(WM8904_POWER_MANAGEMENT_6, WM8904_DACL_ENA | WM8904_DACR_ENA | WM8904_ADCL_ENA | WM8904_ADCR_ENA); delay_ms(5); wm8904_write_register(WM8904_ANALOGUE_LEFT_INPUT_0, WM8904_LIN_VOL(0x10)); wm8904_write_register(WM8904_ANALOGUE_RIGHT_INPUT_0, WM8904_RIN_VOL(0x10)); wm8904_write_register(WM8904_ANALOGUE_HP_0, WM8904_HPL_ENA | WM8904_HPR_ENA); wm8904_write_register(WM8904_ANALOGUE_HP_0, WM8904_HPL_ENA_DLY | WM8904_HPL_ENA | WM8904_HPR_ENA_DLY | WM8904_HPR_ENA); wm8904_write_register(WM8904_DC_SERVO_0, WM8904_DCS_ENA_CHAN_3 | WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_1 | WM8904_DCS_ENA_CHAN_0); wm8904_write_register(WM8904_DC_SERVO_1, WM8904_DCS_TRIG_STARTUP_3 | WM8904_DCS_TRIG_STARTUP_2 | WM8904_DCS_TRIG_STARTUP_1 | WM8904_DCS_TRIG_STARTUP_0); delay_ms(100); wm8904_write_register(WM8904_ANALOGUE_HP_0, WM8904_HPL_ENA_OUTP | WM8904_HPL_ENA_DLY | WM8904_HPL_ENA | WM8904_HPR_ENA_OUTP | WM8904_HPR_ENA_DLY | WM8904_HPR_ENA); wm8904_write_register(WM8904_ANALOGUE_HP_0, WM8904_HPL_RMV_SHORT | WM8904_HPL_ENA_OUTP | WM8904_HPL_ENA_DLY | WM8904_HPL_ENA | WM8904_HPR_RMV_SHORT | WM8904_HPR_ENA_OUTP | WM8904_HPR_ENA_DLY | WM8904_HPR_ENA); wm8904_write_register(WM8904_ANALOGUE_OUT1_LEFT, WM8904_HPOUT_VU | WM8904_HPOUTL_VOL(0x39)); wm8904_write_register(WM8904_ANALOGUE_OUT1_RIGHT, WM8904_HPOUT_VU | WM8904_HPOUTR_VOL(0x39)); } else { wm8904_write_register(WM8904_BIAS_CONTROL_0, WM8904_ISEL_HP_BIAS | WM8904_BIAS_ENA); wm8904_write_register(WM8904_VMID_CONTROL_0, WM8904_VMID_BUF_ENA | WM8904_VMID_RES_NORMAL | WM8904_VMID_ENA); delay_ms(5); wm8904_write_register(WM8904_POWER_MANAGEMENT_0, WM8904_INL_ENA | WM8904_INR_ENA); wm8904_write_register(WM8904_POWER_MANAGEMENT_0, WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA); wm8904_write_register(WM8904_POWER_MANAGEMENT_6, WM8904_DACL_ENA | WM8904_DACR_ENA | WM8904_ADCL_ENA | WM8904_ADCR_ENA); delay_ms(100); wm8904_write_register(WM8904_CLOCK_RATES_0, 0x845E); wm8904_write_register(WM8904_CLOCK_RATES_1, WM8904_CLK_SYS_RATE(3) | WM8904_SAMPLE_RATE(5)); wm8904_write_register(WM8904_CLOCK_RATES_2, WM8904_CLK_SYS_ENA | WM8904_CLK_DSP_ENA); wm8904_write_register(WM8904_AUDIO_INTERFACE_1, 0x0002); delay_ms(100); wm8904_write_register(WM8904_DAC_DIGITAL_1, 0x0000); wm8904_write_register(WM8904_ANALOGUE_LEFT_INPUT_0, WM8904_LIN_VOL(0x5)); wm8904_write_register(WM8904_ANALOGUE_RIGHT_INPUT_0, WM8904_RIN_VOL(0x5)); wm8904_write_register(WM8904_ANALOGUE_LEFT_INPUT_1, 0x0000); wm8904_write_register(WM8904_ANALOGUE_RIGHT_INPUT_1, 0x0000); delay_ms(100); wm8904_write_register(WM8904_ANALOGUE_OUT1_RIGHT, 0x00AD); wm8904_write_register(WM8904_DC_SERVO_0, WM8904_DCS_ENA_CHAN_1 | WM8904_DCS_ENA_CHAN_0); wm8904_write_register(WM8904_ANALOGUE_HP_0, 0x00FF); wm8904_write_register(WM8904_CHARGE_PUMP_0, WM8904_CP_ENA); wm8904_write_register(WM8904_CLASS_W_0, 0x0005); delay_ms(100); } } int main(void) { /* Initialize the SAM system. */ sysclk_init(); board_init(); /* Initialize the console UART. */ configure_console(); puts(STRING_HEADER); /* Initialize WM8904 TWI interface*/ if (wm8904_twi_init() != TWIHS_SUCCESS) { printf("-E-\tWM8904 initialization failed.\r"); while (1) { /* Capture error */ } } /* Configure CODEC */ configure_codec(); /* Configure SSC */ configure_ssc(); /* Configure XDMA */ configure_xdma(); /* Enable the DAC master clock */ pmc_disable_pck(PMC_PCK_2); pmc_pck_set_prescaler(PMC_PCK_2, PMC_MCKR_PRES_CLK_1); if(PCK2 == PMC_MCKR_CSS_SLOW_CLK) { pmc_pck_set_source(PMC_PCK_2, PMC_MCKR_CSS_SLOW_CLK); } else { pmc_pck_set_source(PMC_PCK_2, PMC_MCKR_CSS_MAIN_CLK); } pmc_enable_pck(PMC_PCK_2); /* Start playing */ delay_ms(300); /*This code makes the sscHandlerCount increase, but there is no waveform at codec output*/ NVIC_EnableIRQ(SSC_IRQn); ssc_enable_interrupt(SSC, 0xFFFFFFFF); /* the interrupt does not happen with this code ssc_enable_interrupt(SSC, 0xFFFFFFFF); */ /* the interrupt does not happen with this code NVIC_EnableIRQ(SSC_IRQn);*/ /* NVIC_EnableIRQ(SSC_IRQn); ssc_enable_interrupt(SSC, 0xFFFFFFFF);*/ ssc_enable_tx(SSC); xdmac_channel_enable(XDMAC, XDMA_CH_SSC_TX); while (1) { } } /// @cond 0 /**INDENT-OFF**/ #ifdef __cplusplus } #endif /**INDENT-ON**/ /// @endcond