如何使用 gcc 内联汇编器代码访问成员变量
How to access member variable with gcc inline assembler code
所以我最近偶然发现了这篇博客文章 NeoPixel 揭示:如何(不需要(生成精确定时的信号并支持 github 项目,现在我试图将此代码的核心封装到 c++ 类中,以便我可以从多个 arduino uno 数字引脚访问各种 neopixel 字符串。
为此,我创建了一个受保护的成员变量 (m_PixelChannel(,用于存储访问浅色字符串所需的引脚。但是,我无法让程序集代码识别成员变量。下面是我尝试工作的代码(它或多或少是 github 项目中原始代码的直接复制粘贴,并在它之前添加了类名(:
// send a bit to the string. We must to drop to asm to enusre that the complier does
// not reorder things and make it so the delay happens in the wrong place.
inline void fastNeoPixels::sendBit(bool bitVal) {
if (bitVal) { // 0 bit
asm volatile(
"sbi %[port], %[bit] nt" // Set the output bit
".rept %[onCycles] nt" // Execute NOPs to delay exactly the specified number of cycles
"nop nt"
".endr nt"
"cbi %[port], %[bit] nt" // Clear the output bit
".rept %[offCycles] nt" // Execute NOPs to delay exactly the specified number of cycles
"nop nt"
".endr nt" ::
[port] "I"(_SFR_IO_ADDR(PIXEL_PORT)),
[bit] "r"(m_PixelChannel),
// [bit] "I" (PIXEL_STRING0),
[onCycles] "I"(NS_TO_CYCLES(T1H) - 2), // 1-bit width less overhead for the actual bit setting, note that this delay could be longer and everything would still work
[offCycles] "I"(NS_TO_CYCLES(T1L) - 2) // Minimum interbit delay. Note that we probably don't need this at all since the loop overhead will be enough, but here for correctness
);
} else { // 1 bit
// **************************************************************************
// This line is really the only tight goldilocks timing in the whole program!
// **************************************************************************
asm volatile(
"sbi %[port], %[bit] nt" // Set the output bit
".rept %[onCycles] nt" // Now timing actually matters. The 0-bit must be long enough to be detected but not too long or it will be a 1-bit
"nop nt" // Execute NOPs to delay exactly the specified number of cycles
".endr nt"
"cbi %[port], %[bit] nt" // Clear the output bit
".rept %[offCycles] nt" // Execute NOPs to delay exactly the specified number of cycles
"nop nt"
".endr nt" ::
[port] "I"(_SFR_IO_ADDR(PIXEL_PORT)),
[bit] "r" (m_PixelChannel),
// [bit] "I" (PIXEL_STRING0),
[onCycles] "I"(NS_TO_CYCLES(T0H) - 2),
[offCycles] "I"(NS_TO_CYCLES(T0L) - 2)
);
} // if (bitVal)...
// Note that the inter-bit gap can be as long as you want as long as it doesn't exceed the 5us reset timeout (which is A long time)
// Here I have been generous and not tried to squeeze the gap tight but instead erred on the side of lots of extra time.
// This has thenice side effect of avoid glitches on very long strings becuase
}
我确信m_PixelChannel变量导致了问题;我想这与约束有关,因为我可以通过取消注释PIXEL_STRING0行代码来使其再次工作。或者,我可以将值作为参数传递给方法并使用"n"约束代码使其工作(正如我成功所做的那样(,但我认为我不应该将参数传递给可以访问该值的方法已经...
我尝试了以下约束代码,但没有运气:"n","o","I","m","+m","r"和"g"。
显然我错过了一些东西。请有人指出我正确的方向来完成这项工作吗?
问题是 SBI 指令的操作数必须是常量(即时值(。 因此,唯一有效的约束是I
并且该值必须是常量。 无法设置可变位。
如果要设置可变位,则必须使用类似于 switch 语句的内容来选择 8 个不同的指令之一。
我决定我真的不喜欢我在评论克里斯·多德的回应时使用的模板<>方法。因此,经过多次迭代,我能够弄清楚如何使其工作......
void sendBit( bool bitVal ) {
volatile uint8_t _hi = *m_PixelPORT | m_PinMask;
volatile uint8_t _lo = *m_PixelPORT & ~m_PinMask;
if ( bitVal ) {
asm volatile (
"st %a[port], %[hi]" "nt" // Set the output bit
".rept %[onCycles]" "nt" // Execute NOPs to delay exactly the specified number of cycles
"nop" "nt"
".endr" "nt"
"st %a[port], %[lo]" "nt" // Clear the output bit
".rept %[offCycles]" "nt" // Execute NOPs to delay exactly the specified number of cycles
"nop" "nt"
".endr" "nt"
: [port] "+e" (m_PixelPORT)
: [hi] "r" (_hi),
[lo] "r" (_lo),
[onCycles] "I" (NS_TO_CYCLES(T1H) - 2), // 1-bit width less overhead for the actual bit setting, note that this delay could be longer and everything would still work
[offCycles] "I" (NS_TO_CYCLES(T1L) - 2) // Minimum interbit delay. Note that we probably don't need this at all since the loop overhead will be enough, but here for correctness
);
} else {
asm volatile (
"st %a[port], %[hi]" "nt" // Set the output bit
".rept %[onCycles]" "nt" // Execute NOPs to delay exactly the specified number of cycles
"nop" "nt"
".endr" "nt"
"st %a[port], %[lo]" "nt" // Clear the output bit
".rept %[offCycles]" "nt" // Execute NOPs to delay exactly the specified number of cycles
"nop" "nt"
".endr" "nt"
: [port] "+e" (m_PixelPORT)
: [hi] "r" (_hi),
[lo] "r" (_lo),
[onCycles] "I" (NS_TO_CYCLES(T0H) - 2),
[offCycles] "I" (NS_TO_CYCLES(T0L) - 2)
);
}
}
其中m_PinMask = _BV(digital_pin(;
请注意,对sbi/cbi的调用已替换为对st的调用和约束类型的更改。
应用这些更改使代码完全按照我想做的事情,同时保持在位爆炸过程的计时要求范围内。
再次感谢克里斯为我指出正确的方向!
- 为什么示例代码访问IUnknown中已删除的内存
- 如何使用 gcc 内联汇编器代码访问成员变量
- 在链接的程序集文件中,我想从 c++ 调用代码访问变量.是否可以在不触发访问冲突的情况下执行此操作?
- 使用MySQL C 连接器从C 代码访问MEMSQL
- 无法从C 代码访问C共享库方法
- 是否可以将匿名 lambda 函数绑定到对象以允许 lambda 中的代码访问对象的成员?
- 从本地代码访问apk中的压缩文件(从zip中读取zip)
- Unity 3D:从 C/C++ 代码访问 Unity 3D API
- Xcode c++ 无法通过代码访问文件
- 使用终止进程终止"mstsc.exe"进程时出现错误代码(5)访问被拒绝
- QT 5.4,无法从代码访问资源
- 为什么此代码访问向量超出其范围
- 使本机代码访问java方法和数据成员
- Dll 通过 excel 从 c++ 代码访问
- 通过静态变量从本机代码访问有状态托管对象
- 从标准C++代码访问iPhone的沙盒文档文件夹
- 从代码访问iOS设置
- <canvas> 从 NaCl 代码访问 HTML5
- 从 QT 中的C++代码访问 QML 元素
- 从非托管C++代码访问 WPF