int main(void) { /* * All interrupts to wake up from LPSS state need * to be registered to transition again to LPSS. * * The only wake events for LPSS are RTC, AON GPIO, * AON Counter and AON Comparator. * * All interrupts below will wake up the Sensor Subsystem. */ qm_irq_request(QM_IRQ_RTC_0_INT, dummy_isr); qm_irq_request(QM_IRQ_COMPARATOR_0_INT, dummy_isr); qm_irq_request(QM_IRQ_AONPT_0_INT, dummy_isr); qm_irq_request(QM_IRQ_AON_GPIO_0_INT, dummy_isr); /* Unmask comparator interrupts for the Sensor Subsystenm */ QM_INTERRUPT_ROUTER->comparator_0_ss_halt_int_mask &= ~QM_AC_COMPARATORS_MASK; /* * Enable LPSS by the Sensor Subsystem. * This will clock gate sensor peripherals. */ ss_power_soc_lpss_enable(); /* Loop on SS2 to be ready for LPSS even after wake-up. */ while (1) { ss_power_cpu_ss2(); } return 0; }
int main(void) { qm_gpio_port_config_t cfg; QM_PUTS("Starting: AON GPIO"); /* Request IRQ and write GPIO port config. */ cfg.direction = 0; /* Set all pins as inputs. */ cfg.int_en = BIT(PIN_INTR); /* Interrupt enabled. */ cfg.int_type = BIT(PIN_INTR); /* Edge sensitive interrupt. */ cfg.int_polarity = ~BIT(PIN_INTR); /* Falling edge. */ cfg.int_debounce = BIT(PIN_INTR); /* Debounce enabled. */ cfg.int_bothedge = 0; /* Both edge disabled. */ cfg.callback = aon_gpio_example_callback; cfg.callback_data = NULL; qm_irq_request(QM_IRQ_AON_GPIO_0_INT, qm_aon_gpio_0_isr); qm_gpio_set_config(QM_AON_GPIO_0, &cfg); QM_PUTS("AON GPIO set up, press 'PB0' to trigger the interrupt"); /* Wait for the AON GPIO callback to be invoked and print the status. */ while (!callback_invoked) ; QM_PRINTF("Status of AON GPIO callback = 0x%u \n", callback_status); QM_PUTS("Finished: AON GPIO"); return 0; }
int main(void) { /* Comparator example app * * This app sets up comparator 0 to fire an interrupt when the input * voltage is greater than the reference voltage (0.95V) * * On the Intel(R) Quark(TM) Microcontroller D2000 Development Platform * the pin used is marked "SSO 10" */ qm_ac_config_t ac_cfg; QM_PUTS("Analog Comparators example app start\n"); /* Set up pin muxing and request IRQ*/ qm_pmux_select(QM_PIN_ID_0, QM_PMUX_FN_1); qm_pmux_input_en(QM_PIN_ID_0, true); qm_irq_request(QM_IRQ_AC, qm_ac_isr); /* Write configs */ ac_cfg.reference = BIT(0); /* Ref internal voltage */ ac_cfg.polarity = 0x0; /* Fire if greater than ref (high level) */ ac_cfg.power = BIT(0); /* Normal operation mode */ ac_cfg.int_en = BIT(0); /* AIN0 enable */ ac_cfg.callback = ac_example_callback; qm_ac_set_config(&ac_cfg); QM_PUTS("Analog Comparators example app complete\n"); return 0; }
static void deep_sleep_test(void) { /* * Setup the RTC to get out of sleep mode. deep sleep will require an * analog comparator interrupt to wake up the system. */ uint32_t pmux_sel_save[2], pmux_in_en_save, pmux_pullup_save; qm_ac_config_t ac_cfg; /* * Physical step at this stage to raise the V on the comparator * pin. * * Go to deep sleep, a comparator should wake me up. */ ac_cfg.reference = BIT(WAKEUP_COMPARATOR_PIN); /* Ref internal voltage. */ ac_cfg.polarity = 0x0; /* Fire if greater than ref (high level). */ ac_cfg.power = BIT(WAKEUP_COMPARATOR_PIN); /* Normal operation mode. */ ac_cfg.int_en = BIT(WAKEUP_COMPARATOR_PIN); /* Enable comparator. */ ac_cfg.callback = ac_example_callback; qm_ac_set_config(&ac_cfg); qm_irq_request(QM_IRQ_COMPARATOR_0_INT, qm_comparator_0_isr); /* * Comparator pin will fire an interrupt when the input voltage * is greater than the reference voltage (0.95V). */ /* * In order to minimise power, pmux_sel must be set to 0, input * enable must be cleared for any pins not expecting to be * used to wake the SoC from deep sleep mode, in this example * we are using AC 6. */ pmux_sel_save[0] = QM_SCSS_PMUX->pmux_sel[0]; pmux_sel_save[1] = QM_SCSS_PMUX->pmux_sel[1]; pmux_in_en_save = QM_SCSS_PMUX->pmux_in_en[0]; pmux_pullup_save = QM_SCSS_PMUX->pmux_pullup[0]; QM_SCSS_PMUX->pmux_sel[0] = QM_SCSS_PMUX->pmux_sel[1] = 0; QM_SCSS_PMUX->pmux_in_en[0] = BIT(WAKEUP_COMPARATOR_PIN); QM_SCSS_PMUX->pmux_pullup[0] = 0; /* Mux out comparator. */ qm_pmux_select(QM_PIN_ID_6, QM_PMUX_FN_1); qm_pmux_input_en(QM_PIN_ID_6, true); ENTER_C2LP(); /* Restore previous pinmuxing settings. */ QM_SCSS_PMUX->pmux_sel[0] = pmux_sel_save[0]; QM_SCSS_PMUX->pmux_sel[1] = pmux_sel_save[1]; QM_SCSS_PMUX->pmux_in_en[0] = pmux_in_en_save; QM_SCSS_PMUX->pmux_pullup[0] = pmux_pullup_save; }
int main(void) { qm_gpio_port_config_t cfg; sensor_activation(); QM_PUTS("Starting: Power LPSS"); /* Set GPIO pin muxing. */ qm_pmux_select(PIN_OUT, QM_PMUX_FN_0); qm_pmux_select(PIN_INTR, QM_PMUX_FN_0); /* Request IRQ and write GPIO port config. */ cfg.direction = BIT(PIN_OUT); /* Set PIN_OUT as output. */ cfg.int_en = BIT(PIN_INTR); /* Interrupt enabled. */ cfg.int_type = BIT(PIN_INTR); /* Edge sensitive interrupt. */ cfg.int_polarity = BIT(PIN_INTR); /* Rising edge. */ cfg.int_debounce = BIT(PIN_INTR); /* Debounce enabled. */ cfg.int_bothedge = 0x0; /* Both edge disabled. */ cfg.callback = NULL; cfg.callback_data = NULL; qm_irq_request(QM_IRQ_GPIO_0_INT, qm_gpio_0_isr); qm_gpio_set_config(QM_GPIO_0, &cfg); QM_PUTS("Go to LPSS with x86 core in C2."); /* Wait for the Sensor Subsystem to be ready to transition to LPSS. */ while (!(QM_SCSS_GP->gps2 & QM_SCSS_GP_SENSOR_READY)) ; /* * Go to C2. Sensor Subsystem will perform the transition to LPSS. * Once woken up, SS will wake up the x86 core with the GPIO interrupt. */ power_cpu_c2(); QM_PUTS("Wake up from LPSS."); QM_PUTS("Go to LPSS with x86 core in C2LP."); /* Wait for the Sensor Subsystem to be ready to transition to LPSS. */ while (!(QM_SCSS_GP->gps2 & QM_SCSS_GP_SENSOR_READY)) ; /* * Go to C2LP. Sensor Subsystem will perform the transition to LPSS. * Once woken up, SS will wake up the x86 core with the GPIO interrupt. */ power_cpu_c2lp(); QM_PUTS("Wake up from LPSS."); QM_PUTS("Finished: Power LPSS"); return 0; }
int main(void) { qm_mpr_config_t cfg; uint8_t lower_bound; uint32_t heap_offset, mpr_base; QM_PUTS("Starting: MPR"); /* * The MPR is located in the heap in order to ensure it doesn't clash * with anything so it is necessary to calculate the page number that * corresponds to the start of the heap. */ heap_offset = (uint32_t)&__heap; lower_bound = (uint8_t)((heap_offset - SRAM_BASE) / MPR_PAGE_SIZE) + 1; /* Calculate the physical address of the start of the MPR. */ mpr_base = SRAM_BASE + (lower_bound * MPR_PAGE_SIZE); /* Request the IRQ. */ qm_irq_request(QM_IRQ_SRAM_MPR_0_INT, qm_sram_mpr_0_isr); /* Set the violation policy to trigger an interrupt. */ qm_mpr_set_violation_policy(MPR_VIOL_MODE_INTERRUPT, mpr_example_callback, NULL); /* Configure MPR to allow R/W from DMA agent only. */ cfg.en_lock_mask = QM_SRAM_MPR_EN_MASK_ENABLE; cfg.agent_read_en_mask = QM_SRAM_MPR_AGENT_MASK_DMA; cfg.agent_write_en_mask = QM_SRAM_MPR_AGENT_MASK_DMA; cfg.up_bound = lower_bound; cfg.low_bound = lower_bound; qm_mpr_set_config(QM_MPR_0, &cfg); /* Trigger a violation event by attempting a write inside the MPR. */ REG_VAL(mpr_base + 1) = 0xff; /* Wait for the callback to be invoked. */ while (false == callback_invoked) ; QM_PUTS("MPR Violation!"); QM_PUTS("Finished: MPR"); 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; }
int main(void) { uint32_t c_val = 0, pt_val = 0; qm_aonpt_config_t cfg; QM_PUTS("Starting: Always-on Counter"); /* Always-on Counter enable and read value. */ qm_aonc_enable(QM_AONC_0); if (qm_aonc_get_value(QM_AONC_0, &c_val) == 0) { QM_PRINTF("Always-on Counter value: %u\n", c_val); } else { QM_PUTS("Error: Could not read aonc value."); } /* Request an IRQ and write the Always-on Periodic Timer config. */ cfg.count = 0x1000; /* 0.125 seconds. */ cfg.int_en = true; /* Interrupts enabled. */ cfg.callback = aonpt_example_callback; qm_irq_request(QM_IRQ_AONPT_0_INT, qm_aonpt_0_isr); qm_aonpt_set_config(QM_AONC_0, &cfg); /* Wait for the defined number of callbacks be invoked. */ while (NUM_CALLBACKS > callback_count) ; QM_PRINTF("Periodic Timer callback fired %d times.\n", callback_count); /* Get the value of the Always-on Periodic Timer. */ if (qm_aonpt_get_value(QM_AONC_0, &c_val) == 0) { QM_PRINTF("Always-on Periodic Timer value: %u\n", pt_val); } else { QM_PUTS("Error: Could not read Periodic timer value"); } /* Disable the always-on periodic timer interrupt. */ cfg.int_en = false; qm_aonpt_set_config(QM_AONC_0, &cfg); QM_PUTS("Finished: Always-on counter"); return 0; }
int main(void) { qm_rtc_config_t rtc_cfg; unsigned int count = 0; /* Maximum number of 3-second iterations. */ const unsigned int loop_max = 5; gpio_init(); gpio_set_out(BOARD_LED_PIN, 0); /* Configure the onboard LED pin. */ /* Clear Screen. */ QM_PUTS("Starting: Power Profiler"); QM_PUTS("Low power mode example."); QM_PRINTF("Increment = %d\n", QM_RTC_ALARM_SECOND(CLK_RTC_DIV_1)); clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); /* Initialise RTC configuration: Run, but don't interrupt. */ rtc_cfg.init_val = 0; rtc_cfg.alarm_en = 0; rtc_cfg.alarm_val = QM_RTC_ALARM_SECOND(CLK_RTC_DIV_1); rtc_cfg.callback = rtc_example_callback; rtc_cfg.prescaler = CLK_RTC_DIV_1; qm_rtc_set_config(QM_RTC_0, &rtc_cfg); qm_irq_request(QM_IRQ_RTC_0_INT, qm_rtc_0_isr); test_clock_rates(); /* Enable the RTC Interrupt. */ rtc_cfg.alarm_en = 1; qm_rtc_set_config(QM_RTC_0, &rtc_cfg); count = 0; while (++count < loop_max) { QM_PRINTF("\nC:%d R:%d => ", count, rtc_tick); slow_mode_test(); halt_test(); sleep_test(); #if DEEP_SLEEP deep_sleep_test(); #endif } QM_PUTS("Finished: Power Profiler"); return 0; }
int main(void) { volatile uint32_t delay; uint32_t c_val = 0, pt_val = 0; qm_aonpt_config_t cfg; QM_PUTS("\nAlways-on Counter example app\n"); /* Always-on Counter enable, disable and read value */ qm_aonc_disable(QM_SCSS_AON_0); qm_aonc_enable(QM_SCSS_AON_0); c_val = qm_aonc_get_value(QM_SCSS_AON_0); if (c_val) { QM_PRINTF("Always-on Counter value: %lu\n", c_val); } else { QM_PRINTF("ERROR: Could not read aonc value\n"); } /* Request an IRQ and write the Always-on Periodic Timer config */ cfg.count = 0x10000; cfg.int_en = true; cfg.callback = aonpt_example_callback; qm_irq_request(QM_IRQ_AONPT_0, qm_aonpt_isr_0); qm_aonpt_set_config(QM_SCSS_AON_0, &cfg); /* The AON Periodic Timer runs from the RTC clock at 32KHz (rather than * the system clock which is 32MHz) so we need to spin for a few cycles * allow the register change to propagate */ for (delay = 500; delay--;) { } /* Get the value of the Always-on Periodic Timer */ pt_val = qm_aonpt_get_value(QM_SCSS_AON_0); if (pt_val) { QM_PRINTF("Always-on Periodic Timer value: %lu\n", pt_val); } else { QM_PRINTF("ERROR: Could not read Periodic timer value\n\n"); } QM_PUTS("Always-on counter example app complete\n"); return 0; }
/* 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; }
/* QMSI MPR sample application: this example uses an MPR to pretect a 1kB page of SRAM, and then triggers an MPR violation interrupt. */ int main(void) { qm_mpr_config_t cfg; uint8_t lower_bound; uint32_t heap_offset, sram_base, mpr_base; QM_PUTS("\nMPR example app start"); /* we're going to put this MPR in the heap, to ensure it doesn't clash * with anything else, so we need to figure out the page number that * corresponds to the start of the heap */ heap_offset = (uint32_t)&__heap; /* the IDT lives at the start of SRAM, so __idt_start gives us the SRAM * base address in the Lakemont memory map */ sram_base = (uint32_t)&__idt_start; lower_bound = (uint8_t)((heap_offset - sram_base) / MPR_PAGE_SIZE) + 1; /* get the Lakemont physical address of the start of the MPR */ mpr_base = sram_base + (lower_bound * MPR_PAGE_SIZE); /* Set the violation policy to trigger an interrupt */ qm_irq_request(QM_IRQ_SRAM, qm_mpr_isr); qm_mpr_set_violation_policy(MPR_VIOL_MODE_INTERRUPT, mpr_example_callback); /* Configure MPR to allow R/W from DMA agent */ cfg.en_lock_mask = QM_SRAM_MPR_EN_MASK_ENABLE; cfg.agent_read_en_mask = QM_SRAM_MPR_AGENT_MASK_DMA; cfg.agent_write_en_mask = QM_SRAM_MPR_AGENT_MASK_DMA; cfg.up_bound = lower_bound; cfg.low_bound = lower_bound; qm_mpr_set_config(QM_MPR_0, &cfg); /* trigger a violation event by attempting a write inside the MPR */ REG_VAL(mpr_base + 1) = 0xff; QM_PUTS("MPR example app complete"); return 0; }
/*-------------------------------------------------------------------------*/ void xmodem_io_uart_init() { /* Pinmux for UART_x */ qm_pmux_select(DM_COMM_UART_PIN_TX_ID, DM_COMM_UART_PIN_TX_FN); qm_pmux_select(DM_COMM_UART_PIN_RX_ID, DM_COMM_UART_PIN_RX_FN); qm_pmux_input_en(DM_COMM_UART_PIN_RX_ID, true); /* Enable UART and RTC clocks */ clk_periph_enable(DM_COMM_UART_CLK | CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); /* Setup UART */ qm_uart_set_config(DM_CONFIG_UART, &uart_config); /* Request IRQ for UART */ dm_comm_irq_request(); /* Set up timeout timer (RTC) */ qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0); qm_rtc_set_config(QM_RTC_0, &rtc_cfg); }
int main(void) { qm_gpio_port_config_t cfg; QM_PUTS("AON GPIO example\n"); /* Request IRQ and write GPIO port config */ cfg.direction = 0; /* All pins are input */ cfg.int_en = BIT(PIN_INTR); /* Interrupt enabled */ cfg.int_type = BIT(PIN_INTR); /* Edge sensitive interrupt */ cfg.int_polarity = ~BIT(PIN_INTR); /* Falling edge */ cfg.int_debounce = BIT(PIN_INTR); /* Debounce enabled */ cfg.int_bothedge = 0x0; /* Both edge disabled */ cfg.callback = aon_gpio_example_callback; qm_irq_request(QM_IRQ_AONGPIO_0, qm_aon_gpio_isr_0); qm_gpio_set_config(QM_AON_GPIO_0, &cfg); QM_PUTS("AON GPIO set up, press the Push Button 0 to trigger the " "interrupt\n"); 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"); }
/* QMSI wdt app example */ int main(void) { qm_wdt_config_t wr_cfg; QM_PRINTF("Starting: WDT\n"); wr_cfg.timeout = QM_WDT_2_POW_17_CYCLES; wr_cfg.mode = QM_WDT_MODE_INTERRUPT_RESET; wr_cfg.callback = wdt_example_callback; wdt_fired = 0; qm_wdt_set_config(QM_WDT_0, &wr_cfg); qm_irq_request(QM_IRQ_WDT_0, qm_wdt_isr_0); qm_wdt_start(QM_WDT_0); /* Wait for WDT to fire 10 times and then finish. */ while (wdt_fired < MAX_WDT_FIRINGS) { } QM_PRINTF("Watchdog fired %d times\n", MAX_WDT_FIRINGS); QM_PRINTF("Finished: WDT\n"); return 0; }
int main(void) { qm_rtc_config_t rtc; QM_PUTS("Accelerometer example app\n"); rtc.init_val = 0; rtc.alarm_en = true; rtc.alarm_val = ALARM; rtc.callback = print_accel_callback; qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0); clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); bmc150_init(BMC150_J14_POS_0); bmc150_set_accel_mode(BMC150_MODE_2G); bmc150_set_bandwidth(BMC150_BANDWIDTH_64MS); qm_rtc_set_config(QM_RTC_0, &rtc); return 0; }
SOL_API struct sol_i2c * sol_i2c_open_raw(uint8_t bus, enum sol_i2c_speed speed) { struct sol_i2c *i2c; qm_i2c_config_t cfg; qm_i2c_speed_t bus_speed; qm_rc_t ret; if (bus >= QM_I2C_NUM) { SOL_WRN("I2C bus #%" PRIu8 " doesn't exist.", bus); return NULL; } if ((i2c = buses[bus]) != NULL) return i2c; switch (speed) { case SOL_I2C_SPEED_10KBIT: case SOL_I2C_SPEED_100KBIT: bus_speed = QM_I2C_SPEED_STD; break; case SOL_I2C_SPEED_400KBIT: bus_speed = QM_I2C_SPEED_FAST; break; case SOL_I2C_SPEED_1MBIT: case SOL_I2C_SPEED_3MBIT_400KBIT: bus_speed = QM_I2C_SPEED_FAST_PLUS; break; default: SOL_WRN("Unsupported speed value: %d", speed); return NULL; }; switch (bus) { case QM_I2C_0: qm_irq_request(QM_IRQ_I2C_0, qm_i2c_0_isr); clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_I2C_M0_REGISTER); break; #if QUARK_SE case QM_I2C_1: qm_irq_request(QM_IRQ_I2C_1, qm_i2c_1_isr); clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_I2C_M1_REGISTER); break; #endif case QM_I2C_NUM: /* We checked if we were passed the limit before, so we should never * hit this point. Using all the enum values and no default, however, * allows us to rely on the compiler to know if there are values * we are not considering (depending on warning levels) */ break; } i2c = calloc(1, sizeof(*i2c)); SOL_NULL_CHECK(i2c, NULL); i2c->bus = bus; ret = qm_i2c_get_config(i2c->bus, &cfg); SOL_EXP_CHECK_GOTO(ret != QM_RC_OK, error); cfg.speed = bus_speed; cfg.address_mode = QM_I2C_7_BIT; cfg.mode = QM_I2C_MASTER; cfg.slave_addr = 0; ret = qm_i2c_set_config(i2c->bus, &cfg); SOL_EXP_CHECK_GOTO(ret != QM_RC_OK, error); if (!i2c_irq_event) { bool r; i2c_irq_event = process_alloc_event(); r = sol_mainloop_contiki_event_handler_add(&i2c_irq_event, NULL, i2c_cb_dispatch, NULL); SOL_EXP_CHECK_GOTO(!r, error); } buses[i2c->bus] = i2c; return i2c; error: free(i2c); return NULL; }
int main(void) { #if (QUARK_D2000) int i; qm_adc_config_t cfg; qm_adc_xfer_t xfer; qm_adc_channel_t channels[] = {QM_ADC_CH_8, QM_ADC_CH_9}; uint32_t samples_polled[NUM_SAMPLES_POLLED] = {0}; uint32_t samples_interrupt[NUM_SAMPLES_INTERRUPT] = {0}; QM_PUTS("\nADC example app start"); /* Enable the ADC and set the clock divisor */ clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_ADC | CLK_PERIPH_ADC_REGISTER); clk_adc_set_div(100); /* ADC clock is 320KHz @ 32MHz */ /* Set up pinmux */ qm_pmux_select(QM_PIN_ID_8, QM_PMUX_FN_1); qm_pmux_select(QM_PIN_ID_9, QM_PMUX_FN_1); qm_pmux_input_en(QM_PIN_ID_8, true); qm_pmux_input_en(QM_PIN_ID_9, true); /* Set the mode and calibrate */ qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_NORM_CAL); qm_adc_calibrate(QM_ADC_0); /* Set up config */ cfg.window = 20; /* Clock cycles between the start of each sample */ cfg.resolution = QM_ADC_RES_12_BITS; qm_adc_set_config(QM_ADC_0, &cfg); /******************************* * ADC polled mode example ******************************/ QM_PUTS("ADC polled mode"); /* Set up xfer */ xfer.ch = channels; xfer.ch_len = NUM_CHANNELS; xfer.samples = samples_polled; xfer.samples_len = NUM_SAMPLES_POLLED; /* Run the conversion */ if (qm_adc_convert(QM_ADC_0, &xfer)) { QM_PUTS("ERROR: qm_adc_convert failed"); return 1; } /* Print the values of the samples */ for (i = 0; i < NUM_SAMPLES_POLLED; i++) { QM_PRINTF("%d:%x ", i, (unsigned int)samples_polled[i]); } /******************************* * ADC interrupt mode example ******************************/ QM_PUTS("\nADC interrupt mode"); qm_irq_request(QM_IRQ_ADC_0, qm_adc_0_isr); /* Set up xfer */ xfer.ch = channels; xfer.ch_len = NUM_CHANNELS; xfer.samples = samples_interrupt; xfer.samples_len = NUM_SAMPLES_INTERRUPT; xfer.complete_callback = complete_callback; xfer.error_callback = error_callback; if (qm_adc_irq_convert(QM_ADC_0, &xfer)) { QM_PUTS("ERROR: qm_adc_irq_convert failed"); return 1; } /* Wait for the callback */ while (false == complete) ; for (i = 0; i < NUM_SAMPLES_INTERRUPT; i++) { QM_PRINTF("%d:%x ", i, (unsigned int)samples_interrupt[i]); } QM_PUTS("\nADC example app complete"); #endif /* QUARK_D2000 */ return 0; }
int main(void) { qm_dma_channel_config_t cfg = {0}; static dma_channel_desc_t chan_desc; int return_code, i; QM_PUTS("Starting: DMA"); /* * Request the required interrupts. Depending on the channel used a * different isr is set: * qm_irq_request(QM_IRQ_DMA_0_INT_<channel>, * qm_dma_0_isr_<channel>) */ qm_irq_request(QM_IRQ_DMA_0_INT_0, qm_dma_0_isr_0); qm_irq_request(QM_IRQ_DMA_0_ERROR_INT, qm_dma_0_error_isr); /* Set the controller and channel IDs. */ chan_desc.controller_id = QM_DMA_0; chan_desc.channel_id = QM_DMA_CHANNEL_0; return_code = qm_dma_init(chan_desc.controller_id); if (return_code) { QM_PUTS("ERROR: qm_dma_init"); } /* Configure DMA channel. */ cfg.channel_direction = QM_DMA_MEMORY_TO_MEMORY; cfg.source_transfer_width = QM_DMA_TRANS_WIDTH_8; cfg.destination_transfer_width = QM_DMA_TRANS_WIDTH_8; cfg.source_burst_length = QM_DMA_BURST_TRANS_LENGTH_1; cfg.destination_burst_length = QM_DMA_BURST_TRANS_LENGTH_1; cfg.client_callback = transfer_callback; cfg.transfer_type = QM_DMA_TYPE_SINGLE; /* * Set the context as the channel descriptor. This will allow the * descriptor to be available in the callback. * The callback context is not actually used in this app. It is * provided as an example. */ cfg.callback_context = (void *)&chan_desc; return_code = qm_dma_channel_set_config(chan_desc.controller_id, chan_desc.channel_id, &cfg); if (return_code) { QM_PUTS("ERROR: qm_dma_channel_set_config"); } /* Do the transfers. */ do_transfer(&chan_desc); QM_PUTS("Each RX buffer should contain the full TX buffer string."); QM_PRINTF("TX data: %s\n", tx_data); /* Print copied data. */ for (i = 0; i < NUM_TRANSFERS; i++) { QM_PRINTF("RX data Loop %d: %s\n", i, rx_data[i]); } /* Configure DMA channel for multiblock usage. */ cfg.transfer_type = QM_DMA_TYPE_MULTI_LL; return_code = qm_dma_channel_set_config(chan_desc.controller_id, chan_desc.channel_id, &cfg); if (return_code) { QM_PUTS("ERROR: qm_dma_channel_set_config"); } /* Do the multiblock transfer. */ do_transfer_multi(&chan_desc); QM_PRINTF("RX data (multiblock transfer):\n"); rx_data[1][0] = '\0'; printf("%s\n", (char *)&rx_data[0][0]); QM_PUTS("Finished: DMA"); return 0; }
/* Low power app example */ int main(void) { /* Setup the RTC to get out of sleep mode. deep sleep will require an */ /* analog comparator interrupt to wake up the system. */ /* Variables */ uint32_t pmux_sel_save[2], pmux_in_en_save, pmux_pullup_save; qm_ac_config_t ac_cfg; qm_rtc_config_t rtc_cfg; QM_PUTS("Low power mode example."); clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); /* Initialise RTC configuration. */ rtc_cfg.init_val = 0; rtc_cfg.alarm_en = 1; rtc_cfg.alarm_val = QM_RTC_ALARM_SECOND; rtc_cfg.callback = rtc_example_callback; qm_rtc_set_config(QM_RTC_0, &rtc_cfg); qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0); QM_PUTS("CPU Halt."); /* Halt the CPU, RTC alarm will wake me up. */ cpu_halt(); QM_PUTS("CPU Halt wakeup."); /* Set another alarm one minute from now. */ qm_rtc_set_alarm(QM_RTC_0, QM_RTC[QM_RTC_0].rtc_ccvr + QM_RTC_ALARM_SECOND); QM_PUTS("Go to sleep."); /* Go to sleep, RTC will wake me up. */ soc_sleep(); QM_PUTS("Wake up from sleep."); /* Physical step at this stage to raise the V on the comparator pin. */ /* Go to deep sleep, a comparator should wake me up. */ QM_PUTS("Go to deep sleep."); ac_cfg.reference = BIT(WAKEUP_COMPARATOR_PIN); /* Ref internal voltage */ ac_cfg.polarity = 0x0; /* Fire if greater than ref (high level) */ ac_cfg.power = BIT(WAKEUP_COMPARATOR_PIN); /* Normal operation mode */ ac_cfg.int_en = BIT(WAKEUP_COMPARATOR_PIN); /* Enable comparator */ ac_cfg.callback = ac_example_callback; qm_ac_set_config(&ac_cfg); qm_irq_request(QM_IRQ_AC, qm_ac_isr); /* * Comparator pin will fire an interrupt when the input voltage is * greater than the reference voltage (0.95V). */ /* * In order to minimise power, pmux_sel must be set to 0, input enable * must be cleared for any pins not expecting to be used to wake the * SoC from deep sleep mode, in this example we are using AC 6. */ pmux_sel_save[0] = QM_SCSS_PMUX->pmux_sel[0]; pmux_sel_save[1] = QM_SCSS_PMUX->pmux_sel[1]; pmux_in_en_save = QM_SCSS_PMUX->pmux_in_en[0]; pmux_pullup_save = QM_SCSS_PMUX->pmux_pullup[0]; QM_SCSS_PMUX->pmux_sel[0] = QM_SCSS_PMUX->pmux_sel[1] = 0; QM_SCSS_PMUX->pmux_in_en[0] = BIT(WAKEUP_COMPARATOR_PIN); QM_SCSS_PMUX->pmux_pullup[0] = 0; /* Mux out comparator */ qm_pmux_select(QM_PIN_ID_6, QM_PMUX_FN_1); qm_pmux_input_en(QM_PIN_ID_6, true); soc_deep_sleep(); /* Restore previous pinmuxing settings. */ QM_SCSS_PMUX->pmux_sel[0] = pmux_sel_save[0]; QM_SCSS_PMUX->pmux_sel[1] = pmux_sel_save[1]; QM_SCSS_PMUX->pmux_in_en[0] = pmux_in_en_save; QM_SCSS_PMUX->pmux_pullup[0] = pmux_pullup_save; QM_PUTS("Wake up from deep sleep."); return 0; }
SOL_API struct sol_spi * sol_spi_open(unsigned int bus, const struct sol_spi_config *config) { struct sol_spi *spi; qm_spi_t max_bus_available; int ret; SOL_LOG_INTERNAL_INIT_ONCE; /* QM_SPI_NUM is always considering that both master and the slave * exist, so we can't use it to check the valid buses to use */ #if QUARK_SE max_bus_available = QM_SPI_MST_1; #else max_bus_available = QM_SPI_MST_0; #endif SOL_EXP_CHECK(bus >= max_bus_available, NULL); SOL_NULL_CHECK(config, NULL); #ifndef SOL_NO_API_VERSION if (unlikely(config->api_version != SOL_SPI_CONFIG_API_VERSION)) { SOL_WRN("Couldn't open SPI that has unsupported version '%u', " "expected version is '%u'", config->api_version, SOL_SPI_CONFIG_API_VERSION); return NULL; } #endif if (config->chip_select > 3) { SOL_WRN("Invalid chip_select value '%u'. Value must be between 0 and 3.", config->chip_select); return NULL; } if ((config->bits_per_word < 4) || (config->bits_per_word > 32)) { SOL_WRN("Invalid bits_per_word value '%" PRIu8 "'. Value must be " "between 4 and 32.", config->bits_per_word); return NULL; } spi = calloc(1, sizeof(*spi)); SOL_NULL_CHECK(spi, NULL); if (!spi_irq_event) { bool r; spi_irq_event = process_alloc_event(); r = sol_mainloop_contiki_event_handler_add(&spi_irq_event, NULL, spi_cb_dispatch, NULL); SOL_EXP_CHECK_GOTO(!r, error); } spi->bus = bus; spi->slave = BIT(config->chip_select); spi->config.frame_size = config->bits_per_word - 1; spi->config.transfer_mode = QM_SPI_TMOD_TX_RX; spi->config.bus_mode = config->mode; spi->config.clk_divider = 32000000 / config->frequency; switch (spi->bus) { case QM_SPI_MST_0: clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_SPI_M0_REGISTER); qm_irq_request(QM_IRQ_SPI_MASTER_0, qm_spi_master_0_isr); break; #if QUARK_SE case QM_SPI_MST_1: qm_irq_request(QM_IRQ_SPI_MASTER_1, qm_spi_master_1_isr); break; #endif case QM_SPI_SLV_0: case QM_SPI_NUM: /* We checked if we were passed the limit before, so we should never * hit this point. Using all the enum values and no default, however, * allows us to rely on the compiler to know if there are values * we are not considering (depending on warning levels) */ break; } ret = spi_set_gpio_ss(spi); SOL_INT_CHECK_GOTO(ret, < 0, error); return spi; error: free(spi); return NULL; }
/* QMSI SPI app example */ int main(void) { /* Variables */ qm_spi_config_t cfg; qm_spi_transfer_t polled_xfer_desc; qm_spi_async_transfer_t irq_xfer_desc; unsigned int i; for (i = 0; i < BUFFERSIZE; i++) { tx_buff[i] = i; } /* Mux out SPI tx/rx pins and enable input for rx. */ #if (QUARK_SE) qm_pmux_select(QM_PIN_ID_55, QM_PMUX_FN_1); /* SPI0_M SCK */ qm_pmux_select(QM_PIN_ID_56, QM_PMUX_FN_1); /* SPI0_M MISO */ qm_pmux_select(QM_PIN_ID_57, QM_PMUX_FN_1); /* SPI0_M MOSI */ qm_pmux_select(QM_PIN_ID_58, QM_PMUX_FN_1); /* SPI0_M SS0 */ qm_pmux_select(QM_PIN_ID_59, QM_PMUX_FN_1); /* SPI0_M SS1 */ qm_pmux_select(QM_PIN_ID_60, QM_PMUX_FN_1); /* SPI0_M SS2 */ qm_pmux_select(QM_PIN_ID_61, QM_PMUX_FN_1); /* SPI0_M SS3 */ qm_pmux_input_en(QM_PIN_ID_56, true); #elif(QUARK_D2000) qm_pmux_select(QM_PIN_ID_0, QM_PMUX_FN_2); /* SS0 */ qm_pmux_select(QM_PIN_ID_1, QM_PMUX_FN_2); /* SS1 */ qm_pmux_select(QM_PIN_ID_2, QM_PMUX_FN_2); /* SS2 */ qm_pmux_select(QM_PIN_ID_3, QM_PMUX_FN_2); /* SS3 */ qm_pmux_select(QM_PIN_ID_16, QM_PMUX_FN_2); /* SCK */ qm_pmux_select(QM_PIN_ID_17, QM_PMUX_FN_2); /* TXD */ qm_pmux_select(QM_PIN_ID_18, QM_PMUX_FN_2); /* RXD */ qm_pmux_input_en(QM_PIN_ID_18, true); /* RXD input */ #else #error("Unsupported / unspecified processor detected.") #endif /* Enable the clock to the controller. */ clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_SPI_M0_REGISTER); /* Initialise SPI configuration */ cfg.frame_size = QM_SPI_FRAME_SIZE_8_BIT; cfg.transfer_mode = QM_SPI_TMOD_TX_RX; cfg.bus_mode = QM_SPI_BMODE_0; cfg.clk_divider = SPI_CLOCK_DIV; qm_spi_set_config(QM_SPI_MST_0, &cfg); /* Set up loopback mode by RMW directly to the ctrlr0 register. */ QM_SPI[QM_SPI_MST_0]->ctrlr0 |= BIT(11); qm_spi_slave_select(QM_SPI_MST_0, QM_SPI_SS_0); QM_PRINTF("\nStatus = 0x%08x", qm_spi_get_status(QM_SPI_MST_0)); /* Set up the sync transfer struct and call a polled transfer. */ polled_xfer_desc.tx = tx_buff; polled_xfer_desc.rx = rx_buff; polled_xfer_desc.tx_len = BUFFERSIZE; polled_xfer_desc.rx_len = BUFFERSIZE; qm_spi_transfer(QM_SPI_MST_0, &polled_xfer_desc); /* Compare RX and TX buffers */ /* Also reset the buffers for the IRQ example */ for (i = 0; i < BUFFERSIZE; i++) { QM_CHECK(tx_buff[i] == rx_buff[i], QM_RC_EINVAL); tx_buff[i] = i; rx_buff[i] = 0; } /* Set up the async transfer struct. */ irq_xfer_desc.tx = tx_buff; irq_xfer_desc.rx = rx_buff; irq_xfer_desc.tx_len = BUFFERSIZE; irq_xfer_desc.rx_len = BUFFERSIZE; irq_xfer_desc.id = SPI_EXAMPLE_IRQ_ID; irq_xfer_desc.rx_callback = spi_rx_example_cb; irq_xfer_desc.tx_callback = spi_tx_example_cb; irq_xfer_desc.err_callback = spi_err_example_cb; /* Register driver IRQ. */ qm_irq_request(QM_IRQ_SPI_MASTER_0, qm_spi_master_0_isr); /* Start the async (irq-based) transfer. */ qm_spi_irq_transfer(QM_SPI_MST_0, &irq_xfer_desc); while (1) ; return 0; }
int main(void) { uint32_t flash_base; uint32_t fpr_flash; uint32_t value; uint32_t app_end; uint32_t address; uint8_t low_bound; qm_fpr_config_t cfg = {0}; #if (QUARK_D2000) flash_base = QM_FLASH_REGION_SYS_0_BASE; fpr_flash = QM_FLASH_0; #elif(QUARK_SE) flash_base = QM_FLASH_REGION_SYS_1_BASE; fpr_flash = QM_FLASH_1; #endif QM_PRINTF("Starting: FPR\n"); /* Calculate how much space the application code occupies, so we can * ensure our FPR does not overlap with it */ app_end = (uint32_t)__data_lma + (uint32_t)__data_size; if ((app_end + FPR_SIZE + 1) > FLASH_END) { QM_PRINTF("No free pages. Quitting.\n"); return 0; } /* Calculate 1k-aligned physical flash address for FPR start */ low_bound = ((app_end - flash_base) / FPR_SIZE) + 1; /* Calculate MMIO address of a location inside the FPR */ address = (flash_base + (FPR_SIZE * low_bound)) + 4; /* Set the violation policy to trigger an interrupt */ #if (QUARK_D2000) qm_irq_request(QM_IRQ_FLASH_0, qm_fpr_isr_0); #elif(QUARK_SE) qm_irq_request(QM_IRQ_FLASH_1, qm_fpr_isr_1); #endif qm_fpr_set_violation_policy(FPR_VIOL_MODE_INTERRUPT, fpr_flash, fpr_example_cb, NULL); /* Configure MPR to allow R/W from DMA agent only */ cfg.en_mask = QM_FPR_ENABLE; cfg.allow_agents = QM_FPR_DMA; cfg.up_bound = low_bound + 1; cfg.low_bound = low_bound; qm_fpr_set_config(fpr_flash, QM_FPR_0, &cfg, QM_MAIN_FLASH_SYSTEM); /* Trigger a violation event by attempting to read in the FLASH */ value = REG_VAL(address); while (false == callback_invoked) { } QM_PRINTF("Finished: FPR\n"); value = value; 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; }