Задержки блокировки STM32 не соответствуют отключенным прерываниям
Я работаю на микро STM32F0xx, и у меня есть следующий код, который просто переключает вывод с помощью задержек блокировки (да, я знаю, что задержки блокирования плохие, здесь нет смысла).
uint32_t ticks = 0;
// Disable interrupts
__disable_irq();
for (int bit = 0; bit < 10; bit++) {
// Toggle pin high
WritePin(GPIO_PIN_SET);
ticks = 500;
while (ticks--) {
__NOP();
}
// Toggle pin low
WritePin(GPIO_PIN_RESET);
ticks = 500;
while (ticks--) {
__NOP();
}
// Repeat
WritePin(GPIO_PIN_SET);
ticks = 500;
while (ticks--) {
__NOP();
}
WritePin(GPIO_PIN_RESET);
ticks = 500;
while (ticks--) {
__NOP();
}
}
__enable_irq();
Я отключаю прерывания, чтобы убедиться, что больше ничего не происходит на этом этапе. Когда я определяю эти формы волны, я вижу 10 тактов; однако периоды этих сигналов не все совпадают. Все четные осциллограммы (0,2,4,6,8) имеют одинаковый период, и все нечетные осциллограммы (1,3,5,7,9) имеют одинаковый период, но четные и нечетные осциллограммы значительно отличаются (%12). Четные осциллограммы соответствуют первому переключению задержки, а нечетные - второму в цикле for. Я понятия не имею, почему они будут отличаться по времени. У кого-нибудь есть понимание здесь?
1 ответ
Смотрите эту документацию о NOP
на ядре ARM Cortex-M0:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDJJGFB.html
операция
NOP не выполняет никаких операций и не гарантирует затрат времени. Процессор может удалить его из конвейера до того, как он достигнет стадии выполнения.
Используйте NOP для заполнения, например, чтобы разместить последующие инструкции на 64-битной границе.
К этому необходимо добавить другие переменные факторы, такие как повторное заполнение конвейера (из-за ветвления) и состояния ожидания флэш-памяти (изменяющиеся, потому что блоки команд в разных циклах могут быть не совсем точно выровнены для ускорителя флэш-памяти).
Единственный надежный способ выполнить точные задержки - использовать таймер.