c++ - LTO 破坏代码是否正常,如何避免?
问题描述
我正在使用 Arduino IDE 和AttinyCore为 Attiny85 uC 开发一个声音生成程序,并偶然发现了一个我以前从未遇到过的问题。
定时器初始化打开两个定时器,Timer0 和 Timer1。第一个用于 PWM 输出,第二个用于定时采样率中断。简而言之,这给了我两个字节,OCR0A 和 OCR0B,通过改变我可以输出声音的方式,以及一个在大约 1 处调用的中断。15kHz。一切都在一个文件中完成:setup() 初始化计时器,loop() 将声音渲染到 sample1 和 sample2,而 ISR 将声音输出到 OCR0A 和 OCR0B。
#define F_CPU 8000000UL
#include "Arduino.h"
#include <avr/interrupt.h>
#include <stdlib.h>
#include <avr/io.h>
uint8_t sample1 = 0, sample2 = 0;
uint16_t phase1 = 0, phase2 = 0;
void setup() {
digitalWrite(5, HIGH); // Immedeately turn on this pull-up resistor for the reset pin
pinMode(0, OUTPUT); // Two outputs
pinMode(1, OUTPUT);
cli();
// Turn on PLL and wait while it stabilizes
bitSet(PLLCSR, PLLE);
delayMicroseconds(100);
while(!bitRead(PLLCSR, PLOCK));
bitSet(PLLCSR, PCKE);
bitSet(PLLCSR, LSM); //low speed mode, PLL @ 32MHz.
//Set up the TIM0 timer
TCCR0A = bit(WGM00) | bit(WGM01); //Mode: 011, fast PWM. IMHO regular CTC PWM is superior
TCCR0B = 0; //WGM02 is zero
TCCR0A |= bit(COM0A1); // Channel A: Non-inverting PWM mode (10)
TCCR0A |= bit(COM0B1); // Channel B: Non-inverting PWM mode (10)
bitSet(TCCR0B, CS00); // Timer frequency: CLKio/1 = 8MHz
//Set up the TIM1 timer
TCCR1 = 0; TCNT1 = 0; // Stop and clear the timer
GTCCR = bit(PSR1); //Reset the timer
OCR1A = 255; OCR1C = 255;
TIMSK = bit(OCIE1A); // Interrupt enable
TCCR1 = bit(CTC1) | bit(CS12); //Clock: PLL Clock / 8 = 32MHz / 8 = 4 MHz = CPU Clock / 2
//Final Timer1 config: reset on OCR1C compare
//Interrupt on OCR1A compare
//Frequency: 4MHz / 256 = 15625 Hz
sei();
}
ISR(TIMER1_COMPA_vect)
{
OCR0A = sample1;
OCR0B = sample2;
//Internal oscillators 1, 2
phase1 += 3*255;
phase2 += 3*400;
}
void loop() {
sample1 = phase1 >> 8;
sample2 = phase2 >> 8;
}
使 phase1, phase2, sample1, sample2 volatile 有帮助,但我的问题是 - 为什么?
问题是使用 LTO,-Os 这个代码不起作用。可以通过将计算移至中断,或将计算结果直接分配给综合()函数中的 OCR0A 和 OCR0B 字节来修复它,但是,这不是我想要的行为,因为我想让中断尽可能短。
但是,无论是使用 -O0(完全关闭优化)还是禁用 LTO,此代码都可以工作,但闪存大小会显着增加(使用 -O0 时为 2.3kb,使用 -Os 时为 700B,禁用 LTO,启用 LTO 时为 504b)。
我可以关闭 LTO,但对我来说这似乎是一个肮脏的黑客行为。我的问题是:
禁用 LTO 是不是很脏?
优化器如此剧烈地改变行为是否正常?为什么它在没有 LTO 的情况下工作?
为什么我需要使这些变量变为 volatile 以及如何确定我是否需要使变量变为 volatile(除了简单的反复试验或简单地使它们都变为 volatile?)
除了更改优化器设置和使某些东西变得易变之外,我还能做什么?
会不会是编码风格问题?
关于如何编写优化器不会破坏的代码的任何建议?
解决方案
推荐阅读
- grep - devnagari unicode 文本的正确区域设置
- amazon-web-services - AWS 中的 Kubernetes 负载均衡器服务类型是否等于 NordPort + ELB(NLB)?
- javascript - 如何使用节点 js 控制台拒绝邮递员中的解析消息
- rust - 为什么我的`no_std`程序可以编译,即使它以某种方式依赖`std`
- javascript - 如何计算 CloudFlare Worker 中的 Http 请求标头大小?
- api - 平行点中的 Adalo + 情感 api
- google-cloud-platform - Google Cloud Platform 中 BigQuery 的计划查询中的 FileNotFoundException
- javascript - React - 无法读取未定义的属性“值”
- salesforce - 如何在 Aura 组件中绑定地图的动态键
- android - 如何在最小化应用程序后坚持导航组件目的地