Go Down

Topic: Can not properly set pin13 to low (Read 711 times) previous topic - next topic

Udo Klein

I did the following:

Code: [Select]

#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: [Select]

           "   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
Check out my experiments http://blog.blinkenlight.net

retrolefty

#1
Sep 06, 2009, 09:24 pm Last Edit: Sep 07, 2009, 02:05 am by retrolefty Reason: 1
Why are you not using the standard Arduino setup() and loop() functions rather then using a main() function?

Lefty


Udo Klein

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.
Check out my experiments http://blog.blinkenlight.net

Udo Klein

Aargh!

I thought the bug is in the assembly code, but

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


should have been

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


Sorry for the stupid question.

Cheers, Udo
Check out my experiments http://blog.blinkenlight.net


Go Up