Loading...
  Show Posts
Pages: 1 2 3 [4] 5 6
46  Using Arduino / Programming Questions / Re: Mixing C with Assembler: Assembly code before push instructions in a function on: February 07, 2012, 10:37:57 am
... if they're trampled by a push operation then using one of these as a scratch area while you do the push would not work very well.

... write your ISR handler in assembler, have this save your I/O register in your temp register and then call a 'C'/C++ function for whatever logic you want to code in higher level languages. You sound as if you're comfortable writing in assembler, but if you aren't you could get a starting point by listing the assembler generated for your existing handler.
Excellent suggestion, thanks for the tips!  I am not comfortable writing in assembler, so I am going to list the assembler generated and work from there :-) .  But, I am comfortable living life on the edge!  So I'm going to try it.

My intention is to get the heck out of the way of the compiler as quickly as possible, so I'm thinking I might need 2 assembly instructions:  1 to read the register, the other to save it to a C variable (ie, RAM).

I notice that my idea is not so far fetched, as a matter of fact I found this link: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html .  The ISR_NAKED is what I want.  So, my idea is the following, pseudo-code:

Code:
ISR(PCINT0_vect, ISR_NAKED)
{
    asm (read_in_register_to_r0)
    asm (store_to_ram)
    // The following function call will preserve the registers on the stack.  Since I haven't
    // mucked with any but r0 thus far in my ISR, I should be ok.  The function call will
    // also restore the necessary registers.
    C_function_call();
    asm (reti);
}

I notice that the ISR pushes a whole bunch of registers on the stack.  Function calls do not necessarily save the same large set.  I assume that's because the compiler is smart enough to know that a function may not stomp on all the registers, so it's judicious in its saving.  Thus, it seems to me the ISR is storing such a large set because it doesn't have any foreknowledge of what it should or should not preserve, so it paints with a large brush.

But if the *only* thing my ISR does is as listed:  1. my assembly, 2. call a C function, 3. return, then I assume that the heavy lifting of pushing and popping the necessary registers, if handled solely by the C function call in the ISR, should be sufficient. There are no other dragons lying about out, are there?  Again, assuming my ISR is just that lean.

Right now my ISR looks like this:
Code:
ISR(PCINT0_vect) {
        portD.PCint();
}
...so it's doing two bunches of push/pop operations:  The entry into the ISR, and the entry into the function call, which is overkill.

...Just checking my assumptions...
47  Using Arduino / Programming Questions / Re: Mixing C with Assembler: Assembly code before push instructions in a function on: February 07, 2012, 09:35:33 am
I would like to preserve the state of a register very quickly when the interrupt takes place.

I guess you mean you want to preserve the state of an I/O register at the earliest possible point in an ISR.
Exactly!  You hit the nail on the head.  I am writing a library and I am preserving the state of an I/O register- ostensibly at the time of the interrupt- but with all the push instructions, it takes place some 4 microseconds (I figure) after the actual interrupt.

Quote
Have you thought of a way to do that without using any processor registers? Since you can't know what processor registers are in use you mustn't use them until you have preserved their state so that they can be restored afterwards.
Not really.  I am aware of this:
Quote
Register r0 may be freely used by your assembler code and need not be restored at the end of your code. It's a good idea to use __tmp_reg__ and __zero_reg__ instead of r0 or r1, just in case a new compiler version changes the register usage definitions.
So I believe I can safely use r0.  All I need is to use the in instruction, then save that register to RAM, and I should be good to go.
48  Using Arduino / Programming Questions / Re: Mixing C with Assembler: Assembly code before push instructions in a function on: February 07, 2012, 09:31:00 am

Do you understand the purpose of the push instructions?

Quote
I want to insert some assembler which is to be run before those registers are preserved.

Does the "some assembler" include an in instruction (like your pseudo-code)?


Yes, and yes.  I plan on taking advantage of this:

Quote
Register r0 may be freely used by your assembler code and need not be restored at the end of your code. It's a good idea to use __tmp_reg__ ... instead of r0 or r1, just in case a new compiler version changes the register usage definitions.
49  Using Arduino / Programming Questions / Mixing C with Assembler: Assembly code before push instructions in a function on: February 07, 2012, 01:02:00 am
Hello,
I am calling a function from an interrupt, and due to timing issues I would like to preserve the state of a register very quickly when the interrupt takes place.

The C compiler generates a bunch of code to preserve registers when the ISR (or any function) is called.  I want to insert some assembler which is to be run before those registers are preserved.  Is this possible?  Is there some directive I can add to my asm line to tell it exactly where to inject itself in the C code?  Thanks.

The code looks iike this.  I know- the push instructions are there to preserve registers.  Consider my asm to be pseudo-code; I will figure out how to use __tmp_reg__ if I decide that my efforts are worth it.  Thanks:
Code:
ISR(PCINT2_vect) {
    uint8_t value;
    // I want this to take place before the compiler-created push instructions.
    asm volatile("in %0, %1" : "=r" (value) : "I" (_SFR_IO_ADDR(PORTD)));
    portD.PCint();
}
50  Community / Exhibition / Gallery / Re: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: February 06, 2012, 12:45:57 am
...aaaand, version 1.51 is out.  Fixes a bug in 1.5, that caused the pinState to be incorrectly reported  smiley-roll-sweat  .  It appears to work correctly now.  Apologies for the messup.
51  Community / Exhibition / Gallery / Re: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: February 03, 2012, 10:41:45 pm
I just posted version 1.5.  From the notes:

Code:
Version 1.5 Thu Feb  2 18:09:49 CST 2012
Added the PCintPort::pinState static variable to allow the programmer to query the state
of the pin at the time of interrupt.

Added two new #defines, NO_PIN_STATE and NO_PIN_NUMBER so as to reduce the code
size by 20-50 bytes,and to speed up the interrupt routine slightly by declaring that you
don't care if the static variables PCintPort::pinState and/or PCintPort::arduinoPin are set
and made available to your interrupt routine.
// #define NO_PIN_STATE        // to indicate that you don't need the pinState
// #define NO_PIN_NUMBER       // to indicate that you don't need the arduinoPin
52  Using Arduino / Programming Questions / Re: How to give an Object as an Argument to a Function? (...not to a class method) on: January 21, 2012, 11:30:43 am
Ok, yes that makes sense now I suppose.  I'm not totally happy about it, but at least I understand.

Thanks again!
53  Using Arduino / Programming Questions / Re: How to give an Object as an Argument to a Function? (...not to a class method) on: January 21, 2012, 10:32:18 am
Ok, thanks... I got it now.  But I don't get the separation of files.  I have created classes in the sketch without issue.

My understanding of including files goes like this:  The C preprocessor finds the directive, and for all intents and purposes, what the C++ compiler is presented with is essentially the entire text of the included files, along with the file that contains the include directive, in one flow of textual data.

What difference does pulling the class out of the sketch make?  ...I mean, technically.  What is going on under the covers that we don't see?

Thanks again for your response(s).
54  Using Arduino / Programming Questions / How to give an Object as an Argument to a Function? (...not to a class method) on: January 21, 2012, 09:32:47 am
Hi,
I am trying to give an object as an argument to a function, but I am getting an error:
Code:
class myclass
{
  public:
 
  void yo() {
    Serial.println("Hello");
  }
};

myclass pbs=myclass();

void reportit(pbs& i) {
  //i.yo(); // If this didn't give an error, I would uncomment this method call.ß
  Serial.print("test");
};

void setup()
{
  Serial.begin(115200); Serial.println("---------------------------------------");
};

void loop() {
};

but I get this error:

tmp:-1: error: variable or field 'reportit' declared void
tmp:-1: error: 'pbs' was not declared in this scope
tmp:-1: error: 'i' was not declared in this scope
tmp:11: error: variable or field 'reportit' declared void
tmp:11: error: 'i' was not declared in this scope

...Can you tell me why?
55  Development / Suggestions for the Arduino Project / Re: How to give an Object as an Argument to a Function? (...not to a class method) on: January 21, 2012, 09:29:23 am
OOps, drat- I got a typo and confused the issue.  I will ask this in the programming forum section.

I don't know why people think you can't define classes in the sketch.  I do it all the time, with no issues.
56  Development / Suggestions for the Arduino Project / How to give an Object as an Argument to a Function? (...not to a class method) on: January 21, 2012, 01:38:08 am
Hi,
I am trying to give an object as an argument to a function, but I am getting an error:

Code:
class myclass
{
  public:
 
  void yo() {
    Serial.println("Hello");
  }
};

void reportit(pbs& i) {
  //i.yo(); // If this didn't give an error, I would uncomment this method call.
  Serial.print("test");
};


void setup()
{
  Serial.begin(115200); Serial.println("---------------------------------------");
};

void loop() {
};

But it gives:

tmp:-1: error: variable or field 'reportit' declared void
tmp:-1: error: 'pbs' was not declared in this scope
tmp:-1: error: 'i' was not declared in this scope
tmp:10: error: variable or field 'reportit' declared void
tmp:10: error: 'pbs' was not declared in this scope
tmp:10: error: 'i' was not declared in this scope

Can anyone help?  Thanks.
57  Development / Suggestions for the Arduino Project / Re: Delegate system for member function pointers on: January 21, 2012, 01:34:00 am
Very useful indeed.  Thanks for posting.
58  Using Arduino / Programming Questions / Re: C++ getting address of a function: CALLBACK! on: January 16, 2012, 06:44:55 pm
Code:
[code]
smiley-roll Well, here it is, months later and I've made much progress.

What I wanted to do all along was create a callback- virtual functions to the rescue!  The problem, as Nick mentioned, was that it's not enough in C++ to get the address of a method- in order to correctly identify a method the "this" pointer is required.  Because methods are defined in the Class, but instantiated as part of the payload of an object.

So I have found the below code (at the end) and made a little library (cb.h), and created an Interface (that's Java terminology, don't know if it applies to C++).  A full example will be given at my Tigger library at http://code.google.com/p/tigger/ when I upload it.

One subclasses the CallBackInterface class, e.g.:
Code:
class Tigger : public CallBackInterface {
        public:
        // constructors an whatnot go here
}
implement a method called
Code:
void cbmethod(void)
in your class ("Tigger", above), e.g.:
Code:
void Tigger::cbmethod() {
        uint8_t oldSREG = SREG;
        cli();
        tigermillis = timer0_millis;
        SREG = oldSREG;
        if (tigermillis-startTime <= _delay) return;
        startTime=tigermillis;
        count++;
}
Instantiate the class:
Code:
Tigger myTigger=new Tigger();

Then finally, call the cbmethod from, say, an interrupt (pseudo-code).  First, you need to setup the situation; call
Code:
    addPin(myTigger):
The addPin method would look something like this:
Code:
void PCintPort::addPin(CallBackInterface* cbIface)
{
        InterruptPin p=createPin(arduinoPin, CHANGE);
        // ...nefarious details deleted for brevity
        // cbIface is the object instantiated from a subclass of CallBackInterface
        CallBack<CallBackInterface, void>* my_callback=new CallBack<CallBackInterface, void> (cbIface, &CallBackInterface::cbmethod);
        p->pinCallBack=my_callback;
In the Interrupt code, call the CallBack at your leisure.  All variables in the object are accessible.  This call will actually call the cbmethod passed to it above, and previously defined in the class:
Code:
       (*(p->pinCallBack))();

Here's the code I found:
Code:
/*
  **********************************************************************
  * cb by GreyGnome aka Mike Schwager                                  *
  * version 1.0 Mon Jan 16 09:25:59 CST 2012                           *
  *                                                                    *
  * based on:                                                          *
  *      Variable Parameter Call-Back Template (version 0.0.1)         *
  *                                                                    *
  * Author: Arash Partow - 2000                                        *
  * URL: http://www.partow.net/programming/templatecallback/index.html *
  *                                                                    *
  * Copyright Notice:                                                  *
  * Free use of this library is permitted under the guidelines and     *
  * in accordance with the most current version of the Common Public   *
  * License.                                                           *
  * http://www.opensource.org/licenses/cpl.php                         *
  *                                                                    *
  **********************************************************************
*/


#ifndef INCLUDE_CALLBACK_H
#define INCLUDE_CALLBACK_H

class CallBackInterface
{
   public:

     CallBackInterface() {};

     virtual void cbmethod() {
     };

};

template < class Class, typename ReturnType>
class CallBack
{
   public:

    typedef ReturnType (Class::*Method)(void);

    CallBack(Class* _class_instance, Method _method)
    {
       class_instance = _class_instance;
       method         = _method;
    };

    ReturnType operator()()
    {
       return (class_instance->*method)();
    };

    ReturnType execute()
    {
       return operator()();
    };

    private:

      Class*  class_instance;
      Method  method;

};
#endif
[/code]
59  Using Arduino / Programming Questions / Re: Wire.write vs Wire.send. new problems on: January 15, 2012, 04:35:49 pm
Code:
Wire.write((uint8_t) value);

should work in the way that you describe.  You could use a byte for the value and I don't think the compiler will complain.  In any event, your technique sounds good:  The only difference you should see is that
  • They replaced send() with write
  • They removed send(int value), because in that one it was doing a cast to a uint8_t under the covers, thereby trashing the topmost byte of your 16-bit int.

Significantly, though, the code works the same under the covers.

You must have something else wrong with your code.
60  Community / Exhibition / Gallery / PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins on: January 15, 2012, 08:24:39 am
Version 1.4 is now available at http://code.google.com/p/arduino-pinchangeint/

The PinChangeInt library implements Pin Change interrupts for the Arduino environment. It is a drop in replacement for the PCint library.

What are Pin Change interrupts? The ATmega328p processor at the heart of the Arduino has two different kinds of interrupts: “external”, and “pin change”. There are only two external interrupt pins, INT0 and INT1, and they are mapped to Arduino pins 2 and 3. These interrupts can be set to trigger on RISING or FALLING signal edges, or on low level. The triggers are interpreted by hardware, and the interrupt is very fast. On the other hand there are only 2 such pins on the ATmega328p in the Arduino Uno and Duemilanove.

On the other hand the pin change interrupts can be enabled on any or all of the Arduino's signal pins. They are triggered equally on RISING or FALLING signal edges, so it is up to the interrupt code to set the proper pins to receive interrupts, to determine what happened (which pin? ...did the signal rise, or fall?), and to handle it properly. Furthermore, the pin change interrupts are grouped into 3 “port”s on the MCU, so there are only 3 interrupt vectors (subroutines) for the entire body of 20 pins. This makes the job of resolving the action on a single interrupt even more complicated. The interrupt routine should be fast, but complication is the enemy of speed. The PinChangeInt library is designed to handle the Arduino's pin change interrupts as quickly and reasonably as possible (without using Assembly, that is).

Version 1.4 puts all the code in the .h file, to allow the programmer to configure it through their sketch for minimum ram usage. In earlier versions, it must be configured through the PinChangeIntConfig header file instead.

See the Wiki pages for more information.
Pages: 1 2 3 [4] 5 6