Pages: [1]   Go Down
Author Topic: Can not properly set pin13 to low  (Read 526 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3418
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I did the following:

Code:
#include <WProgram.h>
#include <string.h>
#include <pins_arduino.h>

// will initialize output pin with 1, then measure time for  input pin go to high


typedef int32_t micros_type;

// output pin
const uint8_t c_output_pin = 13; // internal LED is connected to digital pin 13
const uint8_t c_output_pin__bit  = 5;                                    // lookup in pins_arduino.c

// attention: input pin and break pin must use the same port !!!
const uint8_t c_input_pin  = 19;  // used as primary trigger pin
const uint8_t c_input_pin__bit  = 5;


int32_t measure_lag_micros;

int32_t measure_lag() {
        
     pinMode(c_input_pin, INPUT);  
       digitalWrite(c_input_pin, HIGH);
 

      // output to low because we want to trigger with high
      // because the opto coupler will turn this to low again
      pinMode(c_output_pin, OUTPUT);  
        digitalWrite(c_output_pin, HIGH);

      // compute pin ports and bit masks in advance
        volatile uint8_t* in_port   = portInputRegister(digitalPinToPort(c_input_pin));
        volatile uint8_t* out_port  = portInputRegister(digitalPinToPort(c_output_pin));
        //volatile uint8_t* break_port = portInputRegister(digitalPinToPort(c_break_pin));
            uint8_t in_bit     = 1 << c_input_pin__bit;              
            uint8_t out_bit    = 1 << c_output_pin__bit;       

        // ensure that we will never see 0 microseconds in the assembler part
        // this is because it would wrap around and give way to long delays
        // impact is that latency will never be below 1 microsecodns
        const micros_type timeout = 99999999;
        measure_lag_micros = timeout;

    uint8_t tmp = 0;

      cli();    
        // the inline assembler loop will burn 16 cycles or 1 microsecond at 16 MHz
      // for details:
      //            http://www.rn-wissen.de/index.php/Inline-Assembler_in_avr-gcc
      //            http://www.avr-asm-tutorial.net/avr_de/beginner/register.html
      //            http://www.avr-asm-tutorial.net/avr_en/beginner/PDETAIL.html#IOPORTS
        
      __asm__ __volatile__ (            
                              
            //       activate output
            "   eor  %[tmp], %[tmp]"   "\n\t"  // set output to low
            "   st  %a[out_port], %[tmp]" "\n\t"   // now
        
        // the loop below will take exactly 16 cycles per pass = 1us at 16 MHz
            "1: nop"                       "\n\t"
            "   nop"                      "\n\t"
            "   nop"                      "\n\t"
            "   nop"                      "\n\t"
            "   nop"                      "\n\t"
            "   ld  %[tmp], %a[in_port]"  "\n\t" // 2 cycles
            "   and %[tmp], %[in_bit]"    "\n\t" // 1 cycle
            "   cp  %[tmp], %[in_bit]"    "\n\t" // 1 cycle
            "   breq 2f"                       "\n\t" // 1 cycle    // stop timing once we see a high
            "   subi %A[micros],1"             "\n\t" // subtract immediate,  1 cycle
            "   sbci %B[micros],0"             "\n\t" // subtract with carry, 1 cycle
            "   sbci %C[micros],0"             "\n\t" // subtract with carry, 1 cycle
            "   sbci %D[micros],0"             "\n\t" // subtract with carry, 1 cycle
            "   brne 1b"                       "\n\t" //                      2 cycles (1 in the last pass)            
                    
            "2: nop"  "\n\t"
            
            : [micros]     "+a" (measure_lag_micros)   // constraint: simple upper register            
            :              "0"  (measure_lag_micros),  // constraint: use same register as [micros]          
              [in_port]    "e" (in_port),              // constraint: pointer register
              [in_bit]     "a" (in_bit),               // constraint: simple upper register            
              [out_port]   "e" (out_port),             // constraint: pointer register      
              [out_bit]    "a" (out_bit),              // constraint: simple upper register        
              [tmp]        "a" (tmp)                     // constraint: simple upper register      
            :                      
      );

        digitalWrite(c_output_pin, HIGH);      

        measure_lag_micros = timeout - measure_lag_micros;
        
        sei();
        return measure_lag_micros;
}


int main(){

      Serial.begin(115200);  
      Serial.println("ready");

      for (;;) {
            micros_type rv;
            rv = measure_lag();
            if (rv>0) {      
            Serial.println(rv ,DEC); }
      }
}


(Sorry for the messed up tabs).

The issue is: if I code a digitalWrite(13,LOW) it will set pin 13 to low. But if I do not it will not.

However I would expect that

Code:
           "   eor  %[tmp], %[tmp]"   "\n\t"  // set output to low
            "   st  %a[out_port], %[tmp]" "\n\t"   // now

would set pin 13 to low. But it fails to do so. Can anyone hit me with a cluebat?

Cheers, Udo
Logged

Check out my experiments http://blog.blinkenlight.net

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16499
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Why are you not using the standard Arduino setup() and loop() functions rather then using a main() function?

Lefty

« Last Edit: September 06, 2009, 07:05:04 pm by retrolefty » Logged

0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3418
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This code is part of a bigger project. I extracted it. The reason why I do not use the IDE is because I do not like it. It always gives me some kind of trouble. For example I can not define prototypes, compiler errors do not refer to proper line numbers and more. The libraries and the bootloader are a big help, but the IDE not really.

But this is definitely not the issue here. If I move this into a "normal" sketch the issue persists.
Logged

Check out my experiments http://blog.blinkenlight.net

0
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3418
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Aargh!

I thought the bug is in the assembly code, but

Code:
 volatile uint8_t* out_port  = portInputRegister(digitalPinToPort(c_output_pin));

should have been

Code:
 volatile uint8_t* out_port  = portOutputRegister(digitalPinToPort(c_output_pin));

Sorry for the stupid question.

Cheers, Udo
Logged

Check out my experiments http://blog.blinkenlight.net

Toronto, ON
Offline Offline
Full Member
***
Karma: 10
Posts: 233
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

(lowers his cluebat...)

b
Logged


Pages: [1]   Go Up
Jump to: