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