static void ss_gpio_interrupt_example(void) { uint32_t i; QM_PUTS("Starting: SS GPIO interrupt"); /* Enable clock to interrupt controller. */ __builtin_arc_sr(BIT(31) + BIT(0), QM_SS_GPIO_0_BASE + QM_SS_GPIO_LS_SYNC); /* Set SS GPIO pin 2 as OUTPUT. */ __builtin_arc_sr(BIT(2), QM_SS_GPIO_0_BASE + QM_SS_GPIO_SWPORTA_DDR); /* Register the SS GPIO interrupt. */ QM_IR_UNMASK_INTERRUPTS(QM_INTERRUPT_ROUTER->ss_gpio_0_int_mask); qm_ss_irq_request(QM_SS_IRQ_GPIO_0_INT, ss_gpio_interrupt_isr); /* Set the bit 3 to rising edge-sensitive. */ __builtin_arc_sr(BIT(3), QM_SS_GPIO_0_BASE + QM_SS_GPIO_INTTYPE_LEVEL); /* Unmask SS GPIO pin 3 interrupt only. */ __builtin_arc_sr(~BIT(3), QM_SS_GPIO_0_BASE + QM_SS_GPIO_INTMASK); /* Clear SS GPIO interrupt requests. */ __builtin_arc_sr(BIT(3), QM_SS_GPIO_0_BASE + QM_SS_GPIO_PORTA_EOI); /* Enable SS GPIO interrupt. */ __builtin_arc_sr(BIT(3), QM_SS_GPIO_0_BASE + QM_SS_GPIO_INTEN); for (i = 0; i < NUM_LOOPS; i++) { /* * Toggle the SS GPIO 2, will trigger the interrupt on SS * GPIO 3. */ clk_sys_udelay(DELAY); __builtin_arc_sr(BIT(2), QM_SS_GPIO_0_BASE + QM_SS_GPIO_SWPORTA_DR); QM_GPIO[0]->gpio_swporta_dr |= BIT(LED_BIT); clk_sys_udelay(DELAY); __builtin_arc_sr(0, QM_SS_GPIO_0_BASE + QM_SS_GPIO_SWPORTA_DR); QM_GPIO[0]->gpio_swporta_dr &= ~BIT(LED_BIT); } /* Unmask all SS GPIO interrupts. */ __builtin_arc_sr(0xff, QM_SS_GPIO_0_BASE + QM_SS_GPIO_INTMASK); if (counter == NUM_LOOPS) { QM_PUTS("Success"); } else { QM_PUTS("Error: Check are pins 14 and 16 on J14 connector " "short connected?"); } QM_PUTS("Finished: SS GPIO interrupt"); }
/* Writes a page to the EEPROM using IRQ I2C transfer. */ void i2c_irq_write_example() { QM_PUTS("IRQ write"); async_irq_write_xfer.tx = eeprom_irq_write_data; async_irq_write_xfer.tx_len = EEPROM_PAGE_SIZE_BYTES + EEPROM_ADDR_SIZE_BYTES; async_irq_write_xfer.callback = i2c_0_irq_callback; async_irq_write_xfer.callback_data = &id_write; async_irq_write_xfer.rx = NULL; async_irq_write_xfer.rx_len = 0; async_irq_write_xfer.stop = true; if (qm_i2c_master_irq_transfer(QM_I2C_0, &async_irq_write_xfer, EEPROM_SLAVE_ADDR)) { QM_PUTS("Error: IRQ write failed"); } /* Wait until complete flag is set in callback. */ while (!i2c_0_irq_complete) ; if (i2c_0_irq_rc_error) { QM_PUTS("Error: I2C IRQ Transfer failed"); } else { QM_PUTS("I2C IRQ Transfer complete"); } /* Wait for EEPROM to complete the write operation. */ clk_sys_udelay(EEPROM_WRITE_WAIT_TIME_US); }
/* * Returns the start and end RTC times for this busy loop. * Ideally, by examining the TSC and RTC times, we should be able to * identify their correlation. */ static uint64_t rtc_tsc_correlate(unsigned int *rtc_start, unsigned int *rtc_end) { #if (!QM_SENSOR) uint64_t start_tsc; uint64_t end_tsc; #else uint32_t start_tsc; uint32_t end_tsc; #endif retry: *rtc_start = QM_RTC[QM_RTC_0]->rtc_ccvr; start_tsc = get_ticks(); clk_sys_udelay(400); *rtc_end = QM_RTC[QM_RTC_0]->rtc_ccvr; /* To prevent int_32 bit overflow while computing the rtc difference. */ if ((*rtc_end < *rtc_start) && (!((*rtc_start & 0xF0000000) == 0xF0000000))) { goto retry; } end_tsc = get_ticks(); return end_tsc - start_tsc; }
static void wait_rx_callback_timeout(uint32_t timeout) { while (!rx_callback_invoked && timeout) { clk_sys_udelay(WAIT_READ_CB_PERIOD_1MS); timeout--; }; }
/* QMSI timer app example */ int main(void) { /* Variables */ qm_pwm_config_t wr_cfg, rd_cfg; uint32_t lo_cnt, hi_cnt; /* Initialise timer configuration */ wr_cfg.lo_count = 0x100000; wr_cfg.hi_count = 0; wr_cfg.mode = QM_PWM_MODE_TIMER_COUNT; wr_cfg.mask_interrupt = false; wr_cfg.callback = timer_example_callback; /* Enable clocking for the PWM block */ clk_periph_enable(CLK_PERIPH_PWM_REGISTER | CLK_PERIPH_CLK); /* Set the configuration of the Timer */ qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_1, &wr_cfg); /* Register the ISR with the SoC */ qm_irq_request(QM_IRQ_PWM_0, qm_pwm_isr_0); /* Optionally, get config back to see the settings */ qm_pwm_get_config(QM_PWM_0, QM_PWM_ID_1, &rd_cfg); /* Start Timer 2 */ qm_pwm_start(QM_PWM_0, QM_PWM_ID_1); /* Optionally, get the current count values */ qm_pwm_get(QM_PWM_0, QM_PWM_ID_1, &lo_cnt, &hi_cnt); clk_sys_udelay(UDELAY); /* Optionally, reload new values into the Timer */ lo_cnt = 0x40000; hi_cnt = 0; qm_pwm_set(QM_PWM_0, QM_PWM_ID_1, lo_cnt, hi_cnt); clk_sys_udelay(UDELAY); /* Stop the Timer from running */ qm_pwm_stop(QM_PWM_0, QM_PWM_ID_1); /* Disable clocking for the PWM block */ clk_periph_disable(CLK_PERIPH_PWM_REGISTER); return 0; }
static void ss_sw_triggered_interrupt_example(void) { uint32_t i; QM_PUTS("Starting: SW triggered interrupt"); qm_irq_request(QM_IRQ_I2C_1_INT, sw_interrupt_isr); QM_GPIO[0]->gpio_swporta_ddr |= BIT(LED_BIT); for (i = 0; i < NUM_LOOPS; i++) { QM_GPIO[0]->gpio_swporta_dr |= BIT(LED_BIT); clk_sys_udelay(DELAY); QM_GPIO[0]->gpio_swporta_dr &= ~BIT(LED_BIT); clk_sys_udelay(DELAY); /* SW mainpulated interrupt trigger, triggers I2C_1. */ __builtin_arc_sr(QM_IRQ_I2C_1_INT_VECTOR, QM_SS_AUX_IRQ_HINT); } if (counter == NUM_LOOPS) { QM_PUTS("Success"); } else { QM_PUTS("Error: SW interrupt didn't fire correctly"); } QM_PUTS("Finished: SW triggered interrupt"); }
/* Writes a page to the EEPROM using PIO I2C transfer. */ void i2c_pio_write_example() { qm_i2c_status_t status; QM_PUTS("PIO write"); /* Write EEPROM page address then the data. */ if (qm_i2c_master_write(QM_I2C_0, EEPROM_SLAVE_ADDR, eeprom_pio_write_data, sizeof(eeprom_pio_write_data), true, &status)) { QM_PUTS("Error: PIO write failed"); } else { QM_PUTS("I2C PIO TX Transfer complete"); } clk_sys_udelay(EEPROM_WRITE_WAIT_TIME_US); }
int main() { uint8_t payload[3]; QM_PRINTF("Simple nRF24L01 receive example\r\n"); #if defined(RF24_SPI_MULTIBYTE) QM_PRINTF("Using multibyte SPI transfers\r\n"); #else QM_PRINTF("Using single byte SPI transfers\r\n"); #endif if (rf24_init()) { QM_PRINTF("Failed to initialize nRF24L01\r\n"); } else { QM_PRINTF("Initialized nRF24L01 radio. "); if (rf24_is_plus()) { QM_PRINTF("Detected nRF24L01+\r\n"); } else { QM_PRINTF("Detected nRF24L01\r\n"); } } rf24_set_retries(15,15); rf24_open_reading_pipe_uint64(0, 0xAA55AA55AA); rf24_start_listening(); clk_sys_udelay(1000); while(1) { if (rf24_available()) { rf24_read(payload, 3); QM_PRINTF("Received data ... %d,%d,%d\r\n",payload[0],payload[1],payload[2]); #if !defined (RF24_MINIMAL) rf24_print_details(); #endif } } return 0; }
int main(void) { uint32_t baudrate, dtr = 0; int bytes_read; QM_PUTS("Starting: USB CDC ACM Example"); qm_irq_request(QM_IRQ_USB_0_INT, qm_usb_0_isr); /* Enable the USB VBUS on Quark SE DevBoard. */ enable_usb_vbus(); /* Init USB CDC ACM. */ cdc_acm_init(); QM_PUTS("CDC ACM Initialized. Waiting for DTR."); do { cdc_acm_line_ctrl_get(LINE_CTRL_DTR, &dtr); } while (!dtr); QM_PUTS("DTR set, start test."); /* Wait 1 sec for the host to do all settings. */ clk_sys_udelay(ONE_SEC_UDELAY); if (cdc_acm_line_ctrl_get(LINE_CTRL_BAUD_RATE, &baudrate)) { QM_PUTS("Failed to get baudrate, ret code."); } else { QM_PRINTF("Baudrate detected: %d\n", baudrate); } QM_PUTS("USB CDC ACM set. Switch to the USB Serial Console."); cdc_acm_irq_callback_set(interrupt_handler); write_data(banner1, strlen(banner1)); write_data(banner2, strlen(banner2)); /* Enable RX interrupts. */ cdc_acm_irq_rx_enable(); /* Echo the received data. */ while (1) { read_and_echo_data(&bytes_read); } return 0; }
/* * Returns the start and end RTC times for this busy loop. * Ideally, by examining the TSC and RTC times, we should be able to * identify their correlation. */ static uint64_t spin_loop(unsigned int count, unsigned int *rtc_start, unsigned int *rtc_end) { uint64_t start_tsc; retry: *rtc_start = QM_RTC[QM_RTC_0].rtc_ccvr; start_tsc = _rdtsc(); clk_sys_udelay(400); *rtc_end = QM_RTC[QM_RTC_0].rtc_ccvr; if ((*rtc_end < *rtc_start) && (!((*rtc_start & 0xF0000000) == 0xF0000000))) { goto retry; } return _rdtsc() - start_tsc; }
int main(void) { bool do_soc_sleep, sleep_ready; int current_state = 0; QM_PRINTF("Starting: Sleep multicore %s\n", MYNAME); #if !QM_SENSOR sensor_activation(); #endif init_mailbox(); while (current_state < 5) { clk_sys_udelay(DELAY_1_SECOND); state_machine(current_state, &sleep_ready, &do_soc_sleep); /* * In that order, we can force the race condition when both * request sleep. */ if (do_soc_sleep) { request_soc_sleep(); current_state++; } else if (mbox_cb_fired) { mbox_cb_fired = false; qm_mbox_ch_read(mbox_rx, &rx_data); if (rx_data.ctrl == SLEEP_REQ) { soc_sleep_requested(sleep_ready); current_state++; } } } QM_PRINTF("Finished: Sleep multicore %s\n", MYNAME); return 0; }
int main(void) { qm_rtc_config_t rtc_cfg; uint32_t aonc_start; uint32_t rtc_trigger; /* Initialise RTC configuration. */ rtc_cfg.init_val = 0; /* Set initial value to 0. */ rtc_cfg.alarm_en = 1; /* Enable alarm. */ rtc_cfg.alarm_val = QM_RTC_ALARM_SECOND(CLK_RTC_DIV_1); /* 1s alarm. */ rtc_cfg.callback = NULL; rtc_cfg.callback_data = NULL; rtc_cfg.prescaler = CLK_RTC_DIV_1; qm_rtc_set_config(QM_RTC_0, &rtc_cfg); /* * The RTC clock resides in a different clock domain * to the system clock. * It takes 3-4 RTC ticks for a system clock write to propagate * to the RTC domain. * If an entry to sleep is initiated without waiting for the * transaction to complete the SOC will not wake from sleep. */ aonc_start = QM_AONC[QM_AONC_0]->aonc_cnt; while (QM_AONC[QM_AONC_0]->aonc_cnt - aonc_start < RTC_SYNC_CLK_COUNT) { } QM_IR_UNMASK_INT(QM_IRQ_RTC_0_INT); QM_IRQ_REQUEST(QM_IRQ_RTC_0_INT, qm_rtc_0_isr); /* * Enable LPSS by the Sensor Subsystem. * This will clock gate sensor peripherals. */ qm_ss_power_soc_lpss_enable(); /* * Signal to the x86 core that the Sensor Subsystem * is ready to enter LPSS mode. */ QM_SCSS_GP->gps2 |= QM_SCSS_GP_SENSOR_READY; rtc_trigger = switch_rtc_to_level(); /* Go to LPSS, RTC will wake the Sensor Subsystem up. */ qm_ss_power_cpu_ss2(); /* Log the interrupt event in soc_watch. */ SOC_WATCH_LOG_EVENT(SOCW_EVENT_INTERRUPT, QM_IRQ_RTC_0_INT_VECTOR); restore_rtc_trigger(rtc_trigger); /* Clear the SENSOR_READY flag in General Purpose Sticky Register 2. */ QM_SCSS_GP->gps2 &= ~QM_SCSS_GP_SENSOR_READY; /* * Disable LPSS. * This will restore clock gating of sensor peripherals. */ qm_ss_power_soc_lpss_disable(); /* Core still in C2 mode. */ qm_gpio_clear_pin(QM_GPIO_0, PIN_OUT); clk_sys_udelay(GPIO_TOGGLE_DELAY); qm_gpio_set_pin(QM_GPIO_0, PIN_OUT); clk_sys_udelay(GPIO_TOGGLE_DELAY); qm_gpio_clear_pin(QM_GPIO_0, PIN_OUT); /* Set another alarm 1 second from now. */ qm_rtc_set_alarm(QM_RTC_0, QM_RTC[QM_RTC_0]->rtc_ccvr + (QM_RTC_ALARM_SECOND(CLK_RTC_DIV_1))); /* * The RTC clock resides in a different clock domain * to the system clock. * It takes 3-4 RTC ticks for a system clock write to propagate * to the RTC domain. * If an entry to sleep is initiated without waiting for the * transaction to complete the SOC will not wake from sleep. */ aonc_start = QM_AONC[QM_AONC_0]->aonc_cnt; while (QM_AONC[QM_AONC_0]->aonc_cnt - aonc_start < RTC_SYNC_CLK_COUNT) { } /* * Enable LPSS by the Sensor Subsystem. * This will clock gate sensor peripherals. */ qm_ss_power_soc_lpss_enable(); /* * Signal to the x86 core that the Sensor Subsystem * is ready to enter LPSS mode. */ QM_SCSS_GP->gps2 |= QM_SCSS_GP_SENSOR_READY; rtc_trigger = switch_rtc_to_level(); /* Go to LPSS, RTC will wake the Sensor Subsystem up. */ qm_ss_power_cpu_ss2(); /* Log the interrupt event in soc_watch. */ SOC_WATCH_LOG_EVENT(SOCW_EVENT_INTERRUPT, QM_IRQ_RTC_0_INT_VECTOR); restore_rtc_trigger(rtc_trigger); /* Clear the SENSOR_READY flag in General Purpose Sticky Register 2. */ QM_SCSS_GP->gps2 &= ~QM_SCSS_GP_SENSOR_READY; /* * Disable LPSS. * This will restore clock gating of sensor peripherals. */ qm_ss_power_soc_lpss_disable(); /* Core still in C2LP mode. */ qm_gpio_clear_pin(QM_GPIO_0, PIN_OUT); clk_sys_udelay(GPIO_TOGGLE_DELAY); qm_gpio_set_pin(QM_GPIO_0, PIN_OUT); clk_sys_udelay(GPIO_TOGGLE_DELAY); qm_gpio_clear_pin(QM_GPIO_0, PIN_OUT); /* Trigger soc_watch flush. */ SOC_WATCH_TRIGGER_FLUSH(); return 0; }
/* Sample UART0 QMSI application. */ int main(void) { qm_uart_config_t cfg = {0}; qm_uart_status_t uart_status __attribute__((unused)) = 0; int ret __attribute__((unused)); const uint32_t xfer_irq_data = BANNER_IRQ_ID; const uint32_t xfer_dma_data = BANNER_DMA_ID; /* Set divisors to yield 115200bps baud rate. */ /* Sysclk is set by boot ROM to hybrid osc in crystal mode (32MHz), * peripheral clock divisor set to 1. */ cfg.baud_divisor = QM_UART_CFG_BAUD_DL_PACK(0, 17, 6); cfg.line_control = QM_UART_LC_8N1; cfg.hw_fc = false; /* Mux out STDOUT_UART tx/rx pins and enable input for rx. */ #if (QUARK_SE) if (STDOUT_UART == QM_UART_0) { qm_pmux_select(QM_PIN_ID_18, QM_PMUX_FN_0); qm_pmux_select(QM_PIN_ID_19, QM_PMUX_FN_0); qm_pmux_input_en(QM_PIN_ID_18, true); } else { qm_pmux_select(QM_PIN_ID_16, QM_PMUX_FN_2); qm_pmux_select(QM_PIN_ID_17, QM_PMUX_FN_2); qm_pmux_input_en(QM_PIN_ID_17, true); } #elif(QUARK_D2000) if (STDOUT_UART == QM_UART_0) { qm_pmux_select(QM_PIN_ID_12, QM_PMUX_FN_2); qm_pmux_select(QM_PIN_ID_13, QM_PMUX_FN_2); qm_pmux_input_en(QM_PIN_ID_13, true); } else { qm_pmux_select(QM_PIN_ID_20, QM_PMUX_FN_2); qm_pmux_select(QM_PIN_ID_21, QM_PMUX_FN_2); qm_pmux_input_en(QM_PIN_ID_21, true); } #else #error("Unsupported / unspecified processor detected.") #endif clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTA_REGISTER); qm_uart_set_config(STDOUT_UART, &cfg); QM_PRINTF("Starting: UART\n"); /* Synchronous TX. */ ret = qm_uart_write_buffer(STDOUT_UART, (uint8_t *)BANNER_STR, sizeof(BANNER_STR)); QM_ASSERT(0 == ret); /* Register the UART interrupts. */ #if (STDOUT_UART_0) qm_irq_request(QM_IRQ_UART_0, qm_uart_0_isr); #elif(STDOUT_UART_1) qm_irq_request(QM_IRQ_UART_1, qm_uart_1_isr); #endif /* Used on both TX and RX. */ async_xfer_desc.callback_data = (void *)&xfer_irq_data; /* IRQ based TX. */ async_xfer_desc.data = (uint8_t *)BANNER_IRQ; async_xfer_desc.data_len = sizeof(BANNER_IRQ); async_xfer_desc.callback = uart_example_tx_callback; ret = qm_uart_irq_write(STDOUT_UART, &async_xfer_desc); QM_ASSERT(0 == ret); clk_sys_udelay(WAIT_1SEC); /* IRQ based RX. */ rx_callback_invoked = false; async_xfer_desc.data = rx_buffer; async_xfer_desc.data_len = BIG_NUMBER_RX; async_xfer_desc.callback = uart_example_rx_callback; ret = qm_uart_irq_read(STDOUT_UART, &async_xfer_desc); QM_ASSERT(0 == ret); QM_PRINTF("\nWaiting for you to type %d characters... ?\n", BIG_NUMBER_RX); wait_rx_callback_timeout(TIMEOUT_10SEC); if (!rx_callback_invoked) { /* RX complete callback was not invoked, we need to terminate * the transfer in order to grab whatever is available in the RX * buffer. */ ret = qm_uart_irq_read_terminate(STDOUT_UART); QM_ASSERT(0 == ret); } else { /* RX complete callback was invoked and RX buffer was read, we * wait in case the user does not stop typing after entering the * exact amount of data that fits the RX buffer, i.e. there may * be additional bytes in the RX FIFO that need to be read * before continuing. */ clk_sys_udelay(WAIT_5SEC); qm_uart_get_status(STDOUT_UART, &uart_status); if (QM_UART_RX_BUSY & uart_status) { /* There is some data in the RX FIFO, let's fetch it. */ ret = qm_uart_irq_read(STDOUT_UART, &async_xfer_desc); QM_ASSERT(0 == ret); ret = qm_uart_irq_read_terminate(STDOUT_UART); QM_ASSERT(0 == ret); } } /* Register the DMA interrupts. */ qm_irq_request(QM_IRQ_DMA_0, qm_dma_0_isr_0); qm_irq_request(QM_IRQ_DMA_ERR, qm_dma_0_isr_err); /* DMA controller initialization. */ ret = qm_dma_init(QM_DMA_0); QM_ASSERT(0 == ret); /* Used on both TX and RX. */ async_xfer_desc.callback_data = (void *)&xfer_dma_data; /* DMA based TX. */ ret = qm_uart_dma_channel_config(STDOUT_UART, QM_DMA_0, QM_DMA_CHANNEL_0, QM_DMA_MEMORY_TO_PERIPHERAL); QM_ASSERT(0 == ret); async_xfer_desc.data = (uint8_t *)BANNER_DMA; async_xfer_desc.data_len = sizeof(BANNER_DMA); async_xfer_desc.callback = uart_example_tx_callback; ret = qm_uart_dma_write(STDOUT_UART, &async_xfer_desc); QM_ASSERT(0 == ret); clk_sys_udelay(WAIT_1SEC); /* DMA based RX. */ rx_callback_invoked = false; ret = qm_uart_dma_channel_config(STDOUT_UART, QM_DMA_0, QM_DMA_CHANNEL_0, QM_DMA_PERIPHERAL_TO_MEMORY); QM_ASSERT(0 == ret); QM_PUTS("Waiting for data on STDOUT_UART (DMA mode) ..."); async_xfer_desc.data = (uint8_t *)rx_buffer; async_xfer_desc.data_len = BIG_NUMBER_RX; async_xfer_desc.callback = uart_example_rx_callback; ret = qm_uart_dma_read(STDOUT_UART, &async_xfer_desc); QM_ASSERT(0 == ret); wait_rx_callback_timeout(TIMEOUT_10SEC); if (!rx_callback_invoked) { /* RX complete callback was not invoked, we need to terminate * the transfer in order to grab whatever was written in the RX * buffer. */ ret = qm_uart_dma_read_terminate(STDOUT_UART); QM_ASSERT(0 == ret); } QM_PRINTF("\nFinished: UART\n"); return 0; }