简体   繁体   English

如何使用 gcc 内联汇编代码访问成员变量

[英]How to access member variable with gcc inline assembler code

So I've recently stumbled across the blog post NeoPixels Revealed: How to (not need to) generate precisely timed signals and supporting github project and am now trying to encapsulate the heart of this code into a c++ class so that I can access various neopixel strings from multiple arduino uno digital pins.所以我最近偶然发现了博客文章NeoPixels Revealed:如何(不需要)生成精确定时的信号和支持github 项目,现在我正在尝试将这段代码的核心封装到一个 C++ 类中,以便我可以访问各种新像素来自多个 arduino uno 数字引脚的字符串。

To do this, I've created a protected member variable (m_PixelChannel) which stores the pin required to access the light string.为此,我创建了一个受保护的成员变量 (m_PixelChannel),用于存储访问灯串所需的引脚。 However, I can't get the assembly code to recognize the member variable.但是,我无法获得识别成员变量的汇编代码。 Below is the code that I'm trying to make work (which is more-or-less a direct copy-paste of the original code from the github project with a classname added before it):下面是我正在尝试制作的代码(它或多或少是 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] \n\t" // Set the output bit
        ".rept %[onCycles] \n\t"   // Execute NOPs to delay exactly the specified number of cycles
        "nop \n\t"
        ".endr \n\t"
        "cbi %[port], %[bit] \n\t" // Clear the output bit
        ".rept %[offCycles] \n\t"  // Execute NOPs to delay exactly the specified number of cycles
        "nop \n\t"
        ".endr \n\t" ::
        [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] \n\t" // Set the output bit
        ".rept %[onCycles] \n\t"   // 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 \n\t"                 // Execute NOPs to delay exactly the specified number of cycles
        ".endr \n\t"
        "cbi %[port], %[bit] \n\t" // Clear the output bit
        ".rept %[offCycles] \n\t"  // Execute NOPs to delay exactly the specified number of cycles
        "nop \n\t"
        ".endr \n\t" ::
        [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
}

I'm convinced that it is that m_PixelChannel variable causing the problems;我确信是 m_PixelChannel 变量导致了问题; something to do with the constraints I suppose, becuase I can get it to work again by uncommenting the PIXEL_STRING0 line of code.与我想的约束有关,因为我可以通过取消注释 PIXEL_STRING0 代码行使其再次工作。 Alternatively, I could pass the value as a parameter to the method and use the "n" constraint code to get it working (as I have successfully done) but I don't think I should have to pass a parameter to a method that has access to the value already...或者,我可以将该值作为参数传递给该方法并使用“n”约束代码使其工作(因为我已成功完成)但我认为我不应该将参数传递给具有已经访问该值...

I've tried the following constraint codes, with no luck: "n", "o", "I", "m", "+m", "r" and "g".我尝试了以下约束代码,但没有成功:“n”、“o”、“I”、“m”、“+m”、“r”和“g”。

Obviously I am missing something.显然我错过了一些东西。 Can someone, please, point me in the right direction to make this work?请有人指出我正确的方向来完成这项工作吗?

The problem is that the operands to the SBI instruction must be constants (immediate values). 问题在于,SBI指令的操作数必须是常量(立即数)。 So the only constraint that works is I and the value has to be a constant. 因此,唯一有效的约束是I ,并且值必须为常数。 There's no way to set a variable bit. 无法设置可变位。

If you want to set a variable bit, you have to use something like a switch statement to select one of 8 different instructions. 如果要设置可变位,则必须使用类似switch语句之类的方法来选择8种不同的指令之一。

I decided that I really didn't like the template<> approach that I used in the comment to Chris Dodd's response.我决定我真的不喜欢我在对 Chris Dodd 回应的评论中使用的 template<> 方法。 So after a number of iterations, I was able to figure out how to make it work...所以经过多次迭代,我能够弄清楚如何让它工作......

  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]"  "\n\t"        // Set the output bit
        ".rept %[onCycles]"  "\n\t"   // Execute NOPs to delay exactly the specified number of cycles
        "nop"                "\n\t"   
        ".endr"              "\n\t"  
        "st %a[port], %[lo]"  "\n\t"   // Clear the output bit
        ".rept %[offCycles]" "\n\t"   // Execute NOPs to delay exactly the specified number of cycles
        "nop"                "\n\t"
        ".endr"              "\n\t"
        : [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]"  "\n\t"        // Set the output bit
        ".rept %[onCycles]"  "\n\t"   // Execute NOPs to delay exactly the specified number of cycles
        "nop"                "\n\t"   
        ".endr"              "\n\t"  
        "st %a[port], %[lo]"  "\n\t"   // Clear the output bit
        ".rept %[offCycles]" "\n\t"   // Execute NOPs to delay exactly the specified number of cycles
        "nop"                "\n\t"
        ".endr"              "\n\t"
        : [port] "+e" (m_PixelPORT)
        : [hi] "r" (_hi),
          [lo] "r" (_lo),
          [onCycles] "I" (NS_TO_CYCLES(T0H) - 2),
          [offCycles]   "I" (NS_TO_CYCLES(T0L) - 2)
      );
    }
  }  

Where m_PinMask = _BV(digital_pin);其中m_PinMask = _BV(digital_pin);

Notice that the calls to sbi/cbi have been replaced by calls to st and the changes in the constraint-types.请注意,对sbi/cbi的调用已被对st的调用和约束类型的更改所取代。

Applying these changes has the code doing exactly what I'm wanting to do while staying within the timing requirements for the bit-bang process.应用这些更改使代码完全符合我想要做的事情,同时保持在 bit-bang 过程的时间要求内。

Thanks again to Chris for pointing me in the right direction!再次感谢克里斯为我指明了正确的方向!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM