.. _pwm_atm_fifo: Atmosic PWM FIFO Mode ##################### Overview ******** The Atmosic PWM FIFO mode provides advanced waveform generation capabilities beyond standard PWM functionality. It enables complex pattern generation with dual carrier frequencies, automatic sequencing, and interrupt-driven operation. This feature is particularly useful for: * Ringtone generation with multiple tones * IR signal transmission with complex patterns * Audio signal generation with varying frequencies * Any application requiring precise timing of multiple waveform segments Key Features ************ * **Dual Carrier Support**: Two independent carrier frequencies can be configured * **16-Entry FIFO**: Hardware command queue for autonomous pattern execution * **Interrupt-Driven**: Alert and completion callbacks for efficient CPU usage * **DMA Support**: Bulk command loading for high-performance applications * **Flexible Patterns**: Each command can specify 1-16,384 carrier cycles * **Hardware Acceleration**: Offloads pattern generation from CPU Architecture ************ The PWM FIFO mode extends the standard Zephyr PWM API with Atmosic-specific functionality. It uses the upper 8 bits of ``pwm_flags_t`` for mode control while maintaining compatibility with existing PWM applications. Configuration ************* The PWM driver and FIFO mode support are enabled by default. The following configurations are automatically set and do not need to be explicitly mentioned when building: .. code-block:: kconfig CONFIG_PWM_ATM=y CONFIG_PWM_ATM_FIFO=y Device Tree *********** The PWM FIFO mode uses the same device tree configuration as standard PWM: .. code-block:: devicetree &pwm0 { status = "okay"; pinctrl-0 = <&pwm0_default>; pinctrl-names = "default"; }; / { aliases { pwm-0 = &pwm0; }; }; Usage Examples ************** Basic Ringtone Generation ========================== .. code-block:: c #include static void fifo_done_callback(const struct device *dev, uint32_t channel, int error) { if (error < 0) { printk("Ringtone error: %d\n", error); } else { printk("Ringtone completed\n"); } } int generate_ringtone(void) { const struct device *pwm_dev = DEVICE_DT_GET(DT_ALIAS(pwm_0)); int ret; /* Configure carriers */ static const struct pwm_atm_carrier_config carrier1 = { .freq_hz = 1000, /* 1 kHz */ .duty_cycle = 50, }; static const struct pwm_atm_carrier_config carrier2 = { .freq_hz = 2000, /* 2 kHz */ .duty_cycle = 50, }; /* FIFO configuration */ static const struct pwm_atm_fifo_config config = { .carrier1 = &carrier1, .carrier2 = &carrier2, .polarity = 0, .fifo_alert_threshold = 8, .fifo_done_callback = fifo_done_callback, }; /* Initialize FIFO mode with error handling */ ret = pwm_atm_fifo_init(pwm_dev, 0, &config); if (ret < 0) { if (ret == -EINVAL) { printk("Invalid FIFO configuration\n"); } else if (ret == -EBUSY) { printk("FIFO mode already in use\n"); } return ret; } /* Create ringtone pattern */ struct pwm_atm_fifo_cmd pattern[] = { {.carrier = 0, .carrier_on = true, .carrier_count = 100}, {.carrier = 0, .carrier_on = false, .carrier_count = 50}, {.carrier = 1, .carrier_on = true, .carrier_count = 100}, {.carrier = 1, .carrier_on = false, .carrier_count = 50}, }; /* Write commands with validation */ ret = pwm_atm_fifo_write_cmds(pwm_dev, 0, pattern, ARRAY_SIZE(pattern)); if (ret < 0) { if (ret == -ENODEV) { printk("Carrier not configured for commands\n"); } goto cleanup; } /* Start execution */ ret = pwm_atm_fifo_start(pwm_dev, 0); if (ret < 0) { goto cleanup; } /* Wait for completion... */ cleanup: /* Important: Clean up FIFO mode */ pwm_atm_fifo_deinit(pwm_dev, 0); return ret; } DMA Mode Operation ================== For high-performance applications, use DMA mode with pre-formatted commands: .. code-block:: c void generate_pattern_dma(void) { const struct device *pwm_dev = DEVICE_DT_GET(DT_ALIAS(pwm_0)); /* Pre-formatted DMA commands */ static const uint16_t dma_cmds[] = { /* Format: bit[15]=carrier, bit[14]=on/off, bit[13:0]=count-1 */ (0 << 15) | (1 << 14) | 99, /* Carrier1 ON, 100 cycles */ (1 << 15) | (0 << 14) | 49, /* Carrier2 OFF, 50 cycles */ }; pwm_atm_fifo_run_dma(pwm_dev, 0, dma_cmds, ARRAY_SIZE(dma_cmds)); } Limitations *********** * Only one PWM channel can use FIFO mode at a time * FIFO depth is limited to 16 commands * Maximum carrier count per command is 16,384 cycles * At least one carrier must be configured during initialization * Requires Atmosic hardware with PWM FIFO support Performance Considerations ************************** * Use FIFO alert callbacks to refill the queue for continuous operation * DMA mode provides the highest performance for bulk command loading * Consider carrier frequency limits based on system clock (16 MHz) * FIFO mode automatically manages power constraints during operation Troubleshooting *************** Common Issues ============= **FIFO Overflow**: Occurs when commands are written faster than they can be executed. Use :c:func:`pwm_atm_fifo_get_free_slots` to check available space. **Callback Not Called**: Ensure interrupts are enabled and the callback functions are properly registered in the configuration structure. **Invalid Frequency**: Carrier frequencies must be within the supported range (123 Hz to 8 MHz). Check system clock configuration. **Channel Busy**: Only one channel can use FIFO mode at a time. Call :c:func:`pwm_atm_fifo_deinit` on the current channel before initializing another. **Carrier Not Configured**: Commands fail with ``-ENODEV`` when trying to use a carrier that was not configured during initialization. Ensure both carriers are configured if your commands use both ``carrier=0`` and ``carrier=1``. **Both Carriers NULL**: Initialization fails with ``-EINVAL`` if both ``carrier1`` and ``carrier2`` are ``NULL``. At least one carrier must be configured. **Sequential Device Issues**: If a second device fails to initialize after the first device completed, ensure :c:func:`pwm_atm_fifo_deinit` was called on the first device. Debug Tips ========== * Enable PWM debug logging: ``CONFIG_PWM_LOG_LEVEL_DBG=y`` * Use :c:func:`pwm_atm_fifo_is_empty` and :c:func:`pwm_atm_fifo_is_full` to monitor FIFO state * Verify device tree PWM configuration and pin assignments * Check that the PWM device is ready before calling FIFO functions * Always call :c:func:`pwm_atm_fifo_deinit` for proper cleanup and sequential device usage * Check return values from all FIFO functions for proper error handling * Verify carrier configuration matches command usage (``carrier=0`` needs ``carrier1``, ``carrier=1`` needs ``carrier2``) * Use proper error code handling (``-EINVAL``, ``-EBUSY``, ``-ENODEV``, and ``-EOVERFLOW``) for robust applications