| 182 | // ============================================================================= |
| 183 | |
| 184 | inline int attach_timer_handler(const isr_config_t& config, isr_handle_t* out_handle) FL_NOEXCEPT { |
| 185 | if (!config.handler) { |
| 186 | ESP_LOGW(ESP32_IDF3_ISR_TAG, "attachTimerHandler: handler is null"); |
| 187 | return -1; // Invalid parameter |
| 188 | } |
| 189 | |
| 190 | if (config.frequency_hz == 0) { |
| 191 | ESP_LOGW(ESP32_IDF3_ISR_TAG, "attachTimerHandler: frequency_hz is 0"); |
| 192 | return -2; // Invalid frequency |
| 193 | } |
| 194 | |
| 195 | // Allocate handle data |
| 196 | auto handle_owner = fl::make_unique<esp32_idf3_isr_handle_data>(); |
| 197 | auto* handle_data = handle_owner.get(); |
| 198 | if (!handle_data) { |
| 199 | ESP_LOGW(ESP32_IDF3_ISR_TAG, "attachTimerHandler: failed to allocate handle data"); |
| 200 | return -3; // Out of memory |
| 201 | } |
| 202 | |
| 203 | // Allocate a timer |
| 204 | if (!allocate_timer(&handle_data->timer_group, &handle_data->timer_idx)) { |
| 205 | ESP_LOGW(ESP32_IDF3_ISR_TAG, "attachTimerHandler: no free timers available"); |
| 206 | return -4; // No timers available |
| 207 | } |
| 208 | |
| 209 | handle_data->is_timer = true; |
| 210 | handle_data->user_handler = config.handler; |
| 211 | handle_data->user_data = config.user_data; |
| 212 | |
| 213 | // Calculate timer divider and alarm value |
| 214 | // ESP32 APB clock is typically 80MHz |
| 215 | // Timer clock = APB_CLK / divider |
| 216 | // We want: alarm_value = timer_clock / frequency_hz |
| 217 | // |
| 218 | // For flexibility, use a divider that gives good resolution |
| 219 | // Divider range: 2 to 65536 |
| 220 | // Using divider=80 gives 1MHz timer clock (1us resolution) |
| 221 | // Using divider=8 gives 10MHz timer clock (0.1us resolution) |
| 222 | |
| 223 | u16 divider; |
| 224 | u64 alarm_value; |
| 225 | |
| 226 | if (config.frequency_hz > 1000000) { |
| 227 | // For high frequencies, use smaller divider for better resolution |
| 228 | divider = 8; // 10MHz timer clock |
| 229 | u32 timer_clock = 80000000 / divider; // 10MHz |
| 230 | alarm_value = timer_clock / config.frequency_hz; |
| 231 | } else { |
| 232 | // For lower frequencies, use divider=80 for 1MHz (1us resolution) |
| 233 | divider = 80; // 1MHz timer clock |
| 234 | u32 timer_clock = 80000000 / divider; // 1MHz |
| 235 | alarm_value = timer_clock / config.frequency_hz; |
| 236 | } |
| 237 | |
| 238 | // Ensure alarm_value is at least 1 |
| 239 | if (alarm_value == 0) { |
| 240 | ESP_LOGW(ESP32_IDF3_ISR_TAG, "attachTimerHandler: frequency too high (%lu Hz)", |
| 241 | (unsigned long)config.frequency_hz); |
nothing calls this directly
no test coverage detected