altineller 4 Posted August 19, 2014 Share Posted August 19, 2014 Hello, Is there an equivalent of digitalReadFast in arduino? For regarding msp430g2553: how can we do things like reading PINB, PINC and them using them with ands in energia? and would that benefit performance? Best Regards, Quote Link to post Share on other sites
bobnova 59 Posted August 19, 2014 Share Posted August 19, 2014 I don't know if there is an equivalent, then again I didn't know those existed in the first place. I've been learning the direct port manipulation methods. On the speed end of things, I tested a G2553 at 16MHz with my scope. This sketch: void setup() { pinMode(P1_0,OUTPUT); } void loop() { digitalWrite(P1_0,HIGH); digitalWrite(P1_0,LOW); } Toggles the pin at ~119kHz, 8.39 altineller 1 Quote Link to post Share on other sites
David Bender 28 Posted August 19, 2014 Share Posted August 19, 2014 bobnova, great suggestion, but please fix that code ASAP; you need parentheses around binary and &, or | and xor ^ operations since the == takes precedence. And I suggest trying out hex notation as placing 1's and 0's correctly may be tedious for you. Quote Link to post Share on other sites
altineller 4 Posted August 19, 2014 Author Share Posted August 19, 2014 Thank you very much for your excellent explanation. I was playing with some motors with encoders which are 336ppm, so if I had a digitalRead in the interrupt handler, as speed went upto a certain threshold it would read position wrong due to delay in digital read. Best, Quote Link to post Share on other sites
bobnova 59 Posted August 19, 2014 Share Posted August 19, 2014 Fixed the code (I think), thanks for the heads up. I'd only used it with single pins and no ==, just "if (this & that)", which works fine as I guess it changes the priority. For giggles I tested on a launchpad and you're definitely correct. Now I know. That'll save me some serious headaches in the future I bet. I've been exploring hex notation a little bit, but don't have an intuitive grasp on which bit positions are what hex numbers and such. You're the second person to suggest I dig deeper into using hex in the last 18 hours though, so I probably should! I'm just dragging myself out of Arduino/Energia, it's slow going. Encoders are fascinating! I hope this helps your work with them. Quote Link to post Share on other sites
altineller 4 Posted August 19, 2014 Author Share Posted August 19, 2014 @@bobnova hello, is there any reason to if this bit code would not work in an interrupt handler? void recoder() { // P1_4 if(P1IN & 0b00001000) { pulse_count++; } else { pulse_count--; } } I pulled the encoder output from the circuit, and connected it to gnd and vcc and expected the pulse++ and -- statements execute. Unfortunately it is always false P1IN & 0b00001000 Best regards, Quote Link to post Share on other sites
altineller 4 Posted August 19, 2014 Author Share Posted August 19, 2014 Well actually I got it to working with P1_7, but after certain speed it will misread the direction for some reason. I have scope hooked up to encoder outputs, and I see the perfect encoder output. I even got it to behave correctly when I put the wire in ground or vcc the rpm goes + or -, so it is working, but when testing with my pid control program after a certain speed it will read negative rpms, instead of positive which destablizes the pwm. Quote Link to post Share on other sites
bobnova 59 Posted August 19, 2014 Share Posted August 19, 2014 Yeah, you've done what I tend to do, counting from the right you need to include pin 0. You're polling P1_3. That's the major downside to doing it without digitalRead, confusion about 0. Quote Link to post Share on other sites
roadrunner84 466 Posted August 20, 2014 Share Posted August 20, 2014 You could use the shorthands as defined in the msp430 header. Or do it yourself: if (P1IN & BIT4) if (P1IN & (1<<4)) Quote Link to post Share on other sites
grahamf72 169 Posted August 20, 2014 Share Posted August 20, 2014 My preferred method is to create macros to make things more readable. Plus if you change which pin something is connected to, you just need to modify the macros. So for example I might have something like the following: #define RED BIT0 #define RED_ON {P1OUT |= RED;} #define RED_OFF {P1OUT &= ~RED;} #define SWITCH BIT4 #define IS_SWITCH_PRESSED (!(P1IN & SWITCH)) //Switch is active low, so we invert the state. void setup() { pinMode(P1_0, OUTPUT); pinMode(P1_3, INPUT_PULLUP); } void loop() { if (IS_SWITCH_PRESSED) RED_ON; else RED_OFF; } Obviously this little example doesn't warrant the use of direct hardware manipulation, but gives a basic example of how I use the macros. When doing it this way, you do have to be careful to not incorrectly mix pin naming styles. The Energia pin names P1_0, P1_3 etc are NOT synonyms for BIT0, BIT3 etc, so a command like "pinMode(SWITCH, INPUT)" won't give the expected results. Likewise "(P1IN & P1_3)" won't give expected results. Quote Link to post Share on other sites
igor 163 Posted August 21, 2014 Share Posted August 21, 2014 If you want to use the Energia pin numbers/names, something like (*portInputRegister(digitalPinToPort(pin)) & digitalPinToBitMask(pin)) looks like it should work (assuming pin is a constant), but the compiler isn't optimizing it enough (these macros are just table lookups in constant arrays, while the results are knowable at compile time, the compiler doesn't take full advantage of that). However something like this does work: #define compileQuickRead(pin) \ (*compilePortInputRegister(compileDigitalPinToPort(pin)) & compileDigitalPinToBitMask(pin)) // If port is a constant, the compiler just substitutes the right port address // If not, this is quite inefficient (i.e. portInputRegister(port) is better) // Could add something similar for output register // Following macros are specific to the MSP430 launchpad, would need to redefine for Fraunchpad or other pin mappings #ifdef P3IN #define compilePortInputRegister(port) ((1 == port) ? &P1IN : \ ((2 == port) ? &P2IN : ((3 == port) ? &P3IN : portInputRegister(port)))) #else #define compilePortInputRegister(port) ((1 == port) ? &P1IN : \ ((2 == port) ? &P2IN : portInputRegister(port))) #endif #define compileDigitalPinToPort(pin) \ ( (((2 <= pin ) && (7 >= pin)) || (14 == pin) || (15 == pin)) ? 1 : \ ((((8 <= pin) && (13 >= pin)) || (18 == pin) || (19 == pin)) ? 2 : NOT_A_PIN)) #define compileDigitalPinToBitMask(pin) \ ( ((( 2 <= pin) && ( 7 >= pin)) ? BV((pin) - 2)) : \ (((( 8 <= pin) && (13 >= pin)) ? BV((pin) - 8)) : \ ( ((14 == pin) || (19 == pin)) ? BV(6) : \ ( ((15 == pin) || (18 == pin)) ? BV(7) : NOT_A_PIN )))) Caveat, this is just an example/concept. I have not done detailed testing of the pin map in the code above to be sure it works for all pins, etc. It works in testing (i.e. it gives same code as (P1IN & 0b00001000) ), but it might not be right for other ports, etc. Maybe somebody more familiar with the macro processor can suggest how to make the above macros automatically fall back to the Energia table lookup if they are given something other than a constant as argument. (Then you would have something could just use and wouldn't have to worry about what type of argument you gave it). Solved - see below. Quote Link to post Share on other sites
David Bender 28 Posted August 21, 2014 Share Posted August 21, 2014 Make sure you enclose your macro arguments in parentheses when defining the macro, such as #define compilePortInputRegister(port) ((1 == (port)) ? &P1IN : \ ((2 == (port)) ? &P2IN : portInputRegister(port))) Quote Link to post Share on other sites
igor 163 Posted August 21, 2014 Share Posted August 21, 2014 Just got around to looking at digitalWriteFast (should have looked at it first) - it works the same way as the macros I tossed together.It also has the answer to question I posed above about testing the argument to be sure it is a constant - __builtin_constant_p (exp) #define digitalReadFast(pin) \ ((__builtin_constant_p((pin))) ? \ (*compilePortInputRegister(compileDigitalPinToPort((pin))) & compileDigitalPinToBitMask((pin))) : \ digitalRead((pin))) So I guess my answer boils down to - just port digitalReadFast to MSP430.And, as David Bender pointed out, if you are going to use it, incorporate the usual macro safety measures. (e.g., Add parenthesis until it looks like lisp.) Quote Link to post Share on other sites
altineller 4 Posted August 23, 2014 Author Share Posted August 23, 2014 ok my last question: will there be any difference in speed when using macro based methods described above versus this notation? if (P1IN & 0b00000001) {code;} Here is what is inside the interrupt routine void recoder() { if(P1IN & 0b10000000) { pulse_count++; } else { pulse_count--; } } And here is output of my quadrature encoders when motors are running at full speed. (scope is set at 10microSec/div) so I basically trigger an interrupt when the the signal on the top is falling, then read the other encoder output to determine whether it is high or not in order to increment or decrement pulse_count. However, since my encoder is 336ppr, the above code works until certain RPM and after that the rpm will get negative (since it can not catch P1IN & 0b10000000 fast enough. I used the above code and circuit setup perfectly with 3ppr encoders, but when encoder ppr gets high, it will fail. I also wrote code that will determine pulse_count + or - from direction flag and not use encoder output b, but I would like to solve this one. @@bobnova pointed out that it would take 0.605 Quote Link to post Share on other sites
David Bender 28 Posted August 23, 2014 Share Posted August 23, 2014 You're at the point where you should expand your toolset. There are 3 things you need to do: 1) Post all your code when asking for help. That is clearly not your entire interrupt handler because the code you showed does not clear the interrupt flag. 2) Count clock cycles I suggest installing naken_util as it contains a utility to count your clock cycles. simply run naken_util -disasm input.hex > output.txt Then look in your .s file to find the address of your interrupt handler. Correlate this address with the one in the output.txt. If you're not sure how to generate all these files you can refer to this Makefile https://github.com/analog10/UART_DCO_Calibrator/blob/master/Makefile 3) Learn some basic assembly You can't capitalize on your clock cycle count without an understanding of assembler. There are many fine examples on this forum. 4) (yes there is a fourth) Explain why you are bitbanging There are timer peripherals that will latch the encoder value for you and give you some latency to play with. I assume you must be using those for other things. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.