![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
Question about built_in function input_state(SOLVED) |
Posted: Wed Jul 02, 2014 7:28 pm |
|
|
Hi everyone,
I am using dsPIC33EP512MU814 with CCS compiler v5.016
What I am trying to do is to read the states of pins and then process. For easy coding, I put the pins I want to read in a array like
Code: |
static unsigned int16 buttonArray[BUTTON_INPUT_AMOUNT] = {PIN_A1,PIN_A2,PIN_A3,PIN_A4,PIN_A5};
|
and then I use FOR loop to read those pins one by one like:
Code: |
unsigned char checkInd;
for(checkInd = 0; checkInd < BUTTON_INPUT_AMOUNT; checkInd++)
{
transDataBuf[checkInd] = input_state(buttonArray[checkInd]);
}
|
But compiler gives error "Expression must evaluate to a constant".
It looks this function doesn't support in this way. I know I can manually code to read those inputs one by one, but beside that, anyone have a good idea to deal with this scenario?
Thanks for your help and time.
Kind Regards
Mark
Last edited by naughty_mark on Thu Jul 03, 2014 12:43 am; edited 4 times in total |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Jul 02, 2014 8:27 pm |
|
|
compiler is telling you it expects a constant for input_state()'s
argument. it is only able to accept a "pin" argument as a CONST at compile time, not in runtime with VARS .
you have few pins so use SWITCH and do an input_state for each pin .....
will be like 8 lines of 'c code -with the benefit of it being way more
code space, and execution time- efficient than if you COULD get away with your code, using vars
just because you think your 'C for(,,) loop is elegant and compact,
if you tried to generate input_state with VAR args, it will make a bloated mess of wasted clock cycles, and be horribly inefficient as a bonus
.. ![Very Happy](images/smiles/icon_biggrin.gif) |
|
![](templates/subSilver/images/spacer.gif) |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
|
Posted: Wed Jul 02, 2014 9:02 pm |
|
|
asmboy wrote: | compiler is telling you it expects a constant for input_state()'s
argument. it is only able to accept a "pin" argument as a CONST at compile time, not in runtime with VARS .
you have few pins so use SWITCH and do an input_state for each pin .....
will be like 8 lines of 'c code -with the benefit of it being way more
code space, and execution time- efficient than if you COULD get away with your code, using vars
just because you think your 'C for(,,) loop is elegant and compact,
if you tried to generate input_state with VAR args, it will make a bloated mess of wasted clock cycles, and be horribly inefficient as a bonus
.. ![Very Happy](images/smiles/icon_biggrin.gif) |
Thanks for your reply, asmboy.
I understand that I can use SWITCH to solve this problem, and I noticed that function needs "constant" not VAR. The reason that I asked this question is I am doing bootloader with some I/O test feature, and I want that code can be cross-projects plant easily, which means in future I don't need to touch the code, just modify the Variable arrays, that is my real purpose.
I think someone may had that experience before and may have a better solution rather than SWITCH.
Thanks for your help, and if anyone have a better idea, I do appreciate.
Kind Regards
Mark
EDIT: what I can think is because in device header file, there is offset value of pin in memory location, such as
Code: |
#define PIN_A1 22868
|
I wonder if there is any command or ASM instruction to let me use this offset to read the pin state? If yes, what the command is? and that "22868" is the offset of what? |
|
![](templates/subSilver/images/spacer.gif) |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
|
Posted: Wed Jul 02, 2014 9:35 pm |
|
|
Hi guys,
I searched that thread, and the last second poster by ckielstra is useful, but I am still not sure if it works for dsPIC33EP512MU814.
http://www.ccsinfo.com/forum/viewtopic.php?t=46396
If it works, my question will be what should I use with ccs pin definition, I mean for example if PIN_A1 is 22826, what that mean? I can not find relative register information in its document.
Thanks for help |
|
![](templates/subSilver/images/spacer.gif) |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
|
Posted: Wed Jul 02, 2014 10:51 pm |
|
|
Hi guys,
I just tried the method in that thread provided by "ckielstra", it works.
Shift that number right to 3 bits means divided by 8, which will give us the port address, just a little bit different for dsPIC33EP512MU814, it is the bit mask judge, because this micro has 16 pins in a port, so the code will be
Code: |
char input_pin_state(int16 ccs_pin)
{
int16 io_port;
char bitmask;
char retval;
io_port = ccs_pin >> 3; // Get the i/o port address
bitmask = 1 << (ccs_pin & 15); // get mask
retval = (*io_port & bitmask) ? 1 : 0; // Read pin (ret. 0 or 1)
return retval;
}
|
Regards
Mark
EDIT: I found a problem that if the pin number is from 0 to 7, that code is ok, if pin above 7 such as PIN_K13, the reading is always 0. I tried many different ways, and use the code as following but still not work, anyone know what's wrong?
Code: |
char input_pin_state(int16 ccs_pin)
{
int16 io_port;
char bitmask;
char shiftStep,pinNum,retval;
io_port = ccs_pin >> 3; // Get the i/o port address
pinNum = ccs_pin & 15;
if(pinNum < 8)
{
shiftStep = (ccs_pin & 15);
}
else
{
shiftStep = (ccs_pin & 15) - 8;
}
bitmask = 1 << shiftStep; // get mask
retval = ((*(io_port+pinNum/8)) & bitmask)? 1 : 0; // Read pin (ret. 0 or 1)
return retval;
}
|
Last edited by naughty_mark on Thu Jul 03, 2014 12:41 am; edited 2 times in total |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19367
|
|
Posted: Thu Jul 03, 2014 12:22 am |
|
|
_char_ bitmask...... |
|
![](templates/subSilver/images/spacer.gif) |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
|
Posted: Thu Jul 03, 2014 12:36 am |
|
|
Ttelmah wrote: | _char_ bitmask...... |
Thanks Ttelmah,
I just got it works, my previous code has a bug in it. Just re-put it on.
Code: |
char input_pin_state(int16 ccs_pin)
{
int16 io_port;
char bitmask;
char shiftStep,pinNum,retval;
io_port = ccs_pin >> 3; // Get the i/o port address
pinNum = ccs_pin & 15;
if(pinNum < 8)
{
shiftStep = (ccs_pin & 15);
}
else
{
shiftStep = (ccs_pin & 15) - 8;
}
bitmask = 1 << shiftStep; // get mask
retval = ((*io_port) & bitmask)? 1 : 0; // Read pin (ret. 0 or 1)
return retval;
}
|
And it works fine.
Thanks for you guys support. I do appreciate.
Mark |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19367
|
|
Posted: Thu Jul 03, 2014 12:47 am |
|
|
As a comment, you do realise that CCS has a function that does all the masking for your?.
Code: |
char input_pin_state(int16 ccs_pin)
{
int16 * io_port; //ensures bit_test treats the return as 16bit
io_port = ccs_pin >> 3; // Get the i/o port address
return (bit_test((*io_port),(ccs_pin & 15));
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
|
Posted: Thu Jul 03, 2014 1:04 am |
|
|
Whoops~~So that means I don't need to take care of the pin number and its masking, that is very good, I will use that. Thanks for your help, Ttelmah.
EDIT: I just doubt if that bit_test gonna work, because (*io_port) will be a BYTE data, and if pin number is higher than 7 which means (ccs_pin &15) is greater than 7, I doubt that function can find a proper value on a BYTE data with higher bit number. Anyway, I may try it tmr. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19367
|
|
Posted: Thu Jul 03, 2014 1:13 am |
|
|
No.
That's why I made it a _pointer_ to an 'int16'.
The compiler then knows it is dealing with an int16 value. ![Smile](images/smiles/icon_smile.gif) |
|
![](templates/subSilver/images/spacer.gif) |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
|
Posted: Thu Jul 03, 2014 4:32 pm |
|
|
Ttelmah wrote: | No.
That's why I made it a _pointer_ to an 'int16'.
The compiler then knows it is dealing with an int16 value. ![Smile](images/smiles/icon_smile.gif) |
Yes, Ttelmah. You are right. If you use pointer to int16, then that should be fine.
But yesterday, when I tried to solve why the upper byte input reading not correct, and found the bit shift is not right because with my code, the *io_port is a byte value, notice in the code I use "int16 io_port", I just followed the code in the thread, and I thought that is wrong and change to "int16 *io_port", the result is I can compile but when the code implemented there, it will reset the micro, and I guess because ccs_pin is the address in the ROM, and maybe I can not access ROM value by using a pointer which is ok to access var in RAM. that is why I use my current code which posted above.
Maybe I am wrong, but the fact is when I use "int16 *io_port", I got reset.
Thanks for your time.
Mark |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19367
|
|
Posted: Fri Jul 04, 2014 12:33 am |
|
|
It needs one change....
Code: |
char input_pin_state(int16 ccs_pin)
{
int16 * io_port; //ensures bit_test treats the return as 16bit
io_port = (ccs_pin >> 3) & 0xFFFE; // Get the i/o port address
return (bit_test((*io_port),(ccs_pin & 15));
}
|
Note the mask.
The chip errors because as originally posted it was trying to access an odd address, when values are above 7. It can't do a 16bit fetch from an odd address.
You could use the internal function, and 8bit fetches, with:
Code: |
char input_pin_state(int16 ccs_pin)
{
int8 * io_port; //8bit return data
io_port = (ccs_pin >> 3); // Get the i/o port address
return (bit_test((*io_port),(ccs_pin & 7));
}
|
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
|
Posted: Sun Jul 06, 2014 5:20 pm |
|
|
Thanks Ttelmah. That makes sense. I do appreciate for your help~ ![Smile](images/smiles/icon_smile.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19367
|
|
Posted: Mon Jul 07, 2014 12:26 am |
|
|
It's worth just adding one comment.
You were using:
int16 io_port;
and accessing with:
retval = ((*io_port) & bitmask)? 1 : 0;
This is potentially slightly dangerous.
It _relies_ on the assumption that the compiler will treat 'io_port' as a pointer to an int8.
Problem is that this is not guaranteed, so it only takes CCS to change this assumption on a future compiler version, and it'll stop working, or crash.
Better either to declare io_port as "int8 * io_port", or explicitly cast it when you use it. So:
retval = ((*(int8 *)io_port) & bitmask)? 1 : 0;
These are the nasty little 'waiting to catch you' problems, that being explicit with types, helps to reduce. C is not explicitly typed, so 'allows' you to use an int16 as a pointer, without casting. On many languages this would not be accepted without an explicit cast (or the equivalent in that language), but while C's flexibility here is useful, it also brings with it dangers/responsibility....
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
naughty_mark
Joined: 29 Aug 2012 Posts: 97
|
|
Posted: Tue Jul 08, 2014 1:03 am |
|
|
Very valuable point, Ttelmah. I will be wary of that and do explicit cast just in case like you said.
I do appreciate your great help and I learnt a lot.
Kind Regards
Mark |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|