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: 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: 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. 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: 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? 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: 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: 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(); }
|
|
|
|
|
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: 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
|
|
|
|
|
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: 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?
|
|
|
|
|
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: 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.
|
|
|
|
|
58
|
Using Arduino / Programming Questions / Re: C++ getting address of a function: CALLBACK!
|
on: January 16, 2012, 06:44:55 pm
|
[code]  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.: class Tigger : public CallBackInterface { public: // constructors an whatnot go here }
implement a method called void cbmethod(void) in your class ("Tigger", above), e.g.: void Tigger::cbmethod() { uint8_t oldSREG = SREG; cli(); tigermillis = timer0_millis; SREG = oldSREG; if (tigermillis-startTime <= _delay) return; startTime=tigermillis; count++; }
Instantiate the class: Tigger myTigger=new Tigger();
Then finally, call the cbmethod from, say, an interrupt (pseudo-code). First, you need to setup the situation; call addPin(myTigger):
The addPin method would look something like this: 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: (*(p->pinCallBack))();
Here's the code I found: /* ********************************************************************** * 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
|
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.
|
|
|
|
|