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:
CONFIG_PWM_ATM=y
CONFIG_PWM_ATM_FIFO=y
Device Tree
The PWM FIFO mode uses the same device tree configuration as standard PWM:
&pwm0 {
status = "okay";
pinctrl-0 = <&pwm0_default>;
pinctrl-names = "default";
};
/ {
aliases {
pwm-0 = &pwm0;
};
};
Usage Examples
Basic Ringtone Generation
#include <zephyr/drivers/pwm_atm_fifo.h>
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:
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 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
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 pwm_atm_fifo_deinit() was called on the first device.
Debug Tips
Enable PWM debug logging:
CONFIG_PWM_LOG_LEVEL_DBG=yUse
pwm_atm_fifo_is_empty()andpwm_atm_fifo_is_full()to monitor FIFO stateVerify device tree PWM configuration and pin assignments
Check that the PWM device is ready before calling FIFO functions
Always call
pwm_atm_fifo_deinit()for proper cleanup and sequential device usageCheck return values from all FIFO functions for proper error handling
Verify carrier configuration matches command usage (
carrier=0needscarrier1,carrier=1needscarrier2)Use proper error code handling (
-EINVAL,-EBUSY,-ENODEV, and-EOVERFLOW) for robust applications