ATmega2560使用Timer0测量矩阵乘法执行时间异常问题
问题:ATmega2560矩阵乘法计时结果不匹配
我正在尝试测量ATmega2560执行矩阵乘法的耗时,采用正常模式的Timer0,通过计数溢出中断次数实现。设置了两种配置:1ms触发一次中断,1μs触发一次中断,但结果异常:毫秒计时得到44ms,微秒计时仅得到366μs(预期至少约44000μs,两种模式结果应对应匹配)。
Timer0配置代码
/* * * Contador con TIMER0 * Normal mode * Interrupciones. Datasheet capitulo 16. * */ #include "timer.h" volatile uint16_t timer0_overflow_count = 0; void timer0_init(uint8_t resolution) { uint8_t prescaler = 0; if (resolution == RESOLUTION_MS) { prescaler = (1 << CS01) | (1 << CS00); // Prescaler 64 TCNT0 = 6; } else if (resolution == RESOLUTION_US) { prescaler = (1 << CS01); // Prescaler 8 TCNT0 = 254; } // Habilitar la interrupción de overflow TIMSK0 |= (1 << TOIE0); // Iniciar el timer TCCR0B = prescaler; // Habilitar interrupciones globales sei(); } // Función para obtener el tiempo transcurrido uint16_t timer0_getCount() { return timer0_overflow_count; } // Rutina de interrupción para el desbordamiento del TIMER0 ISR(TIMER0_OVF_vect) { timer0_overflow_count++; }
主程序代码
/* * * El tamaño máximo de memoria disponible para matrices en ram es * 8 Kb * */ #include <avr/io.h> #include <stdlib.h> #include <util/delay.h> #include <uart.h> #include <timer.h> #define F_CPU 16000000 uint8_t const n = 32; uint8_t* A, * B, * C; // blink builtin led void error() { while (1) { PORTB |= (1 << 7); _delay_ms(20); PORTB &= ~(1 << 7); _delay_ms(200); } } // perform matrix product void multiplicar() { for (uint8_t i = 0; i < n; i++) { for (uint8_t j = 0; j < n; j++) { for (uint8_t k = 0; k < n; k++) { C[i * n + j] += A[i * n + k] * B[j * n + k]; } } } } // Validates operation result void validar() { for (uint16_t i = 0; i < n * n; i++) { if (C[i] != n) { error(); //bloqueante } } } int main() { DDRB |= (1<<7); // Led UART_Init(); A=(uint8_t*)malloc(n*n*sizeof(uint8_t)); B=(uint8_t*)malloc(n*n*sizeof(uint8_t)); C=(uint8_t*)malloc(n*n*sizeof(uint8_t)); // Check if there was enough memory if (A == NULL || B==NULL || C == NULL){ error(); } // Initialize matrices for (int i = 0; i < n*n; i++) { A[i]=1; B[i]=1; C[i]=0; } uint8_t res= RESOLUTION_US; timer0_init(res); multiplicar(); uint16_t time = timer0_getCount(); validar(); // Print elapsed time UART_PrintStr("Tiempo transcurrido: "); UART_PrintNumber(time); (res == RESOLUTION_MS) ? UART_PrintStr(" ms\n") : UART_PrintStr(" us\n"); while (1) { } return 0; }
问题根源分析
- Timer0未重载初始值:正常模式下,Timer0溢出后会从0开始计数,而非你设置的初始值。你的代码只在初始化时设置了
TCNT0,但未在中断服务函数(ISR)中重新加载该值,导致第一次溢出后,后续溢出周期变为256个时钟周期(远大于预期的1μs/1ms),计数结果完全失真。 - 16位计数变量读取无原子操作:
timer0_overflow_count是uint16_t类型,主程序读取时可能被中断打断,导致读取到错误的中间值。 - 微秒模式中断开销过大:每1μs触发一次中断会占用大量CPU时间,不仅拉长矩阵乘法的实际执行时间,还可能因ISR执行时间超过中断周期导致中断丢失。
解决方法
1. 修复Timer0重载逻辑
修改Timer0代码,在ISR中重新加载初始TCNT0值,保证每次溢出周期一致:
#include "timer.h" volatile uint16_t timer0_overflow_count = 0; static uint8_t tcnt0_initial; // 存储初始计数值 void timer0_init(uint8_t resolution) { uint8_t prescaler = 0; if (resolution == RESOLUTION_MS) { prescaler = (1 << CS01) | (1 << CS00); // Prescaler 64 tcnt0_initial = 6; } else if (resolution == RESOLUTION_US) { prescaler = (1 << CS01); // Prescaler 8 tcnt0_initial = 254; } TCNT0 = tcnt0_initial; // 设置初始计数 TIMSK0 |= (1 << TOIE0); // 启用溢出中断 TCCR0B = prescaler; // 启动定时器 sei(); // 开启全局中断 } // 原子操作读取计数,避免中断干扰 uint16_t timer0_getCount() { uint16_t count; cli(); // 临时关闭中断 count = timer0_overflow_count; sei(); // 恢复中断 return count; } ISR(TIMER0_OVF_vect) { timer0_overflow_count++; TCNT0 = tcnt0_initial; // 重新加载初始值,维持固定溢出周期 }
2. 优化微秒计时模式
将微秒模式的溢出周期调整为10μs或100μs,减少中断开销:
- 以10μs为例:计算初始
TCNT0值为256 - (10μs / (1/(16e6/8))) = 236,修改tcnt0_initial = 236,最终计时结果需乘以10得到实际微秒数。
3. 矩阵乘法内存优化
将矩阵B转置,让内存访问变为连续模式,减少缓存失效,提升运算速度:
// 转置矩阵B void transpose(uint8_t* mat, uint8_t size) { for (uint8_t i = 0; i < size; i++) { for (uint8_t j = i+1; j < size; j++) { uint8_t temp = mat[i*size + j]; mat[i*size + j] = mat[j*size + i]; mat[j*size + i] = temp; } } } // 修改multiplicar函数 void multiplicar() { transpose(B, n); // 先转置B for (uint8_t i = 0; i < n; i++) { for (uint8_t j = 0; j < n; j++) { for (uint8_t k = 0; k < n; k++) { C[i * n + j] += A[i * n + k] * B[j * n + k]; } } } }
内容的提问来源于stack exchange,提问作者lautar0
相关产品推荐
相关产品推荐

