@JonnyMac said:
Doesn't Catalina's _pinw() function mimic pinwrite() from Spin2?
How do I do a pin group with _pinw()? I saw this from another thread: pingroup := basepin ADDPINS count
is ADDPINS defined somewhere? How would I write this in c? I need to control 8 bits from pin 32 to 39. Or any group of 8 bits...
The Spin2 addpins feature works like this: pingroup = LSB | ((MSB-LSB) << 6)
I don't think there is a function like that in C.
I don't know how inline assembly works in Catalina. If it's available, one could borrow the code from the Spin2 interpreter. This is from the interpreter moved to inline PASM in Spin2
pub spin_pinw(pingroup, value) | mask
org
ror pingroup, #6 wc
bitc pinw_reg, #9 ' get & set out? register
bmask mask, pingroup ' mask for added pin count
rol pingroup, #6 ' restore pin group
rol mask, pingroup ' align with lsb
rol value, pingroup ' align with lsb
setq mask ' prep selected pins
pinw_reg muxq outa, value ' update
dirh pingroup ' make outputs
end
Ok, so that worked for the B port but does not work for the A port. I wrote the same code but replaced the B with A and nothing. What I am trying to do is toggle based on an eight-bit value.
Works for me on a P2 EDGE with a breakout board. I tried several different groups of 8 pins and it works on both port A and B.
@JonnyMac said:
I don't know how inline assembly works in Catalina. If it's available, one could borrow the code from the Spin2 interpreter. This is from the interpreter moved to inline PASM in Spin2
Here is JonnyMac's code in Catalina inline PASM:
#include <stdint.h>
#ifdef __CATALINA_NATIVE
void spin_pinw(uint32_t pingroup, uint32_t value) {
// note: 'value' is passed in r2, 'pingroup' in r3
// for 'mask' we can use r0
PASM(
" ror r3, #6 wc\n"
" bitc pinw_reg, #9 ' get & set out? register\n"
" bmask r0, r3 ' mask for added pin count\n"
" rol r3, #6 ' restore pin group\n"
" rol r0, r3 ' align with lsb\n"
" rol r2, r3 ' align with lsb\n"
" setq r0 ' prep selected pins\n"
"pinw_reg muxq outa, r2 ' update\n"
" dirh r3 ' make outputs\n"
);
}
#else
#error This implementation of spin_pinw will only work in NATIVE mode.
#endif
NOTE: I have no idea what this does and have not tested it!
NOTE 2: The above PASM is only for NATIVE mode - the syntax of PASM is different in other modes (e.g. COMPACT, LARGE). So I have added a #error statement to warn about this.
NOTE: I have no idea what this does and have not tested it!
It writes value to one or more outputs pins -- though the group must be confined to OUTA or OUTB. The lower six bits of pingroup is the LSB, and bits 6..10 determine how many additional (contiguous) pins are part of the group.
NOTE: I have no idea what this does and have not tested it!
It writes value to one or more outputs pins -- though the group must be confined to OUTA or OUTB. The lower six bits of pingroup is the LSB, and bits 6..10 determine how many additional (contiguous) pins are part of the group.
@JonnyMac said:
I don't know how inline assembly works in Catalina. If it's available, one could borrow the code from the Spin2 interpreter. This is from the interpreter moved to inline PASM in Spin2
Here is JonnyMac's code in Catalina inline PASM:
#include <stdint.h>
void spin_pinw(uint32_t pingroup, uint32_t value) {
// note: 'value' is passed in r2, 'pingroup' in r3
// for 'mask' we can use r0
PASM(
" ror r3, #6 wc\n"
" bitc pinw_reg, #9 ' get & set out? register\n"
" bmask r0, r3 ' mask for added pin count\n"
" rol r3, #6 ' restore pin group\n"
" rol r0, r3 ' align with lsb\n"
" rol r2, r3 ' align with lsb\n"
" setq r0 ' prep selected pins\n"
"pinw_reg muxq outa, r2 ' update\n"
" dirh r3 ' make outputs\n"
);
}
NOTE: I have no idea what this does and have not tested it!
This works on another microcontroller and the function they have is:
/**
* @brief Set GPIO Port OUT Data
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD, PE, PF, PG or PH.
* @param[in] u32Data GPIO port data.
*
* @return None
*
* @details Set the Data into specified GPIO port.
* \hideinitializer
*/
As you can see it is pretty similar to the Propeller 2 by sending the data to the 32-bit pins output register. The way I have done it with the other microcontroller works fantastic and with the Propeller 2 it isn't working.
I wonder if I have _pinh() and _pinl() functions active would they overwrite the OUTA and OUTB writes? I have eeprom and two other I2C devices on P0 - P5 and I have serial ports on P48 - P55. Just curious if those pins are active would they overwrite the 8 bits data trying to go out?
@JonnyMac said:
I don't know how inline assembly works in Catalina. If it's available, one could borrow the code from the Spin2 interpreter. This is from the interpreter moved to inline PASM in Spin2
Here is JonnyMac's code in Catalina inline PASM:
#include <stdint.h>
void spin_pinw(uint32_t pingroup, uint32_t value) {
// note: 'value' is passed in r2, 'pingroup' in r3
// for 'mask' we can use r0
PASM(
" ror r3, #6 wc\n"
" bitc pinw_reg, #9 ' get & set out? register\n"
" bmask r0, r3 ' mask for added pin count\n"
" rol r3, #6 ' restore pin group\n"
" rol r0, r3 ' align with lsb\n"
" rol r2, r3 ' align with lsb\n"
" setq r0 ' prep selected pins\n"
"pinw_reg muxq outa, r2 ' update\n"
" dirh r3 ' make outputs\n"
);
}
NOTE: I have no idea what this does and have not tested it!
This works on another microcontroller and the function they have is:
/**
* @brief Set GPIO Port OUT Data
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD, PE, PF, PG or PH.
* @param[in] u32Data GPIO port data.
*
* @return None
*
* @details Set the Data into specified GPIO port.
* \hideinitializer
*/
As you can see it is pretty similar to the Propeller 2 by sending the data to the 32-bit pins output register. The way I have done it with the other microcontroller works fantastic and with the Propeller 2 it isn't working.
I wonder if I have _pinh() and _pinl() functions active would they overwrite the OUTA and OUTB writes? I have eeprom and two other I2C devices on P0 - P5 and I have serial ports on P48 - P55. Just curious if those pins are active would they overwrite the 8 bits data trying to go out?
I can confirm that the "drive_port" bits toggle when commanded through a debug serial connection I set up.
It would be better if you posted actual code. For instance, what is "_OUTB"?
I wonder if I have _pinh() and _pinl() functions active would they overwrite the OUTA and OUTB writes? I have eeprom and two other I2C devices on P0 - P5 and I have serial ports on P48 - P55. Just curious if those pins are active would they overwrite the 8 bits data trying to go out?
If you are using the same pins, then that seems very likely. Try testing with pins that are not used for other purposes.
It would be better if you posted actual code. For instance, what is "_OUTB"? _OUTB is from the propeller2.h file. Is it not the same as "OUTB" from the propeller.h file?
I wonder if I have _pinh() and _pinl() functions active would they overwrite the OUTA and OUTB writes? I have eeprom and two other I2C devices on P0 - P5 and I have serial ports on P48 - P55. Just curious if those pins are active would they overwrite the 8 bits data trying to go out?
If you are using the same pins, then that seems very likely. Try testing with pins that are not used for other purposes.
I am using pins 32 to 39 for the 8-bit output port. These pins are dedicated to outputting the 8-bits data only and not used for any other function.
Ross.
Where can I find the functions for _pinh(), pinl() etc? When calling these functions do, they also write to OUTA or OUTB registers? When I do something like this:
_DIRB |= 0x000000FF;
_OUTB = 0x000000FF;
Then all eight outputs turn on but this is called when the chip initializes. When used in the code I attached earlier I do not see the outputs pulsing...
Ok, so that worked for the B port but does not work for the A port. I wrote the same code but replaced the B with A and nothing. What I am trying to do is toggle based on an eight-bit value.
Works for me on a P2 EDGE with a breakout board. I tried several different groups of 8 pins and it works on both port A and B.
What board and pins are you using specifically?
Ross.
I have the P2 EVAL board. Pins 32 to 39 are the outputs I am trying to write to.
Given you're at the LSB end of outb and always want to write eight bits, it seems like this might be the way to go (it works in when tested inline with Spin2).
void write3239(uint8_t bits)
{
PASM(
" andn outb, #$FF ' clear p32..p39 \n"
" or outb, r2 ' write to p32..p39 \n"
" or dirb, #$FF ' set to outputs \n"
);
}
Note: I could never get productive with Catalina so I have it, but don't use it. The first parameter passed seems to be in r2 based on Ross's update of my code (above) and examples I've found. BTW, look for .s files in the Catalina folder; they seem to hold function source code..
Where can I find the functions for _pinh(), pinl() etc? When calling these functions do, they also write to OUTA or OUTB registers? When I do something like this:
_DIRB |= 0x000000FF;
_OUTB = 0x000000FF;
Then all eight outputs turn on but this is called when the chip initializes. When used in the code I attached earlier I do not see the outputs pulsing...
My bad - I had forgotten that I had agreed with the other C compiler makers that on the P2 we would use _DIRA etc, not DIRA. Actually, if you include both <propeller.h> and <propeller2.h> you can use either or both in Catalina. But that's not the issue.
I suspect your problem is actually that initialization code, or some similar code elsewhere. If you set an output 'high' in one cog, you cannot then set it 'low' from another. The logic of how pins are combined is described quite well in the Propeller 1 documentation - I could not find the equivalent description in the Propeller 2 documentation, but it would be similar:
The cog collective determines Pin Directions and Pin Outputs as follows:
1. Pin Directions are the result of OR'ing the Direction Registers of the cogs together.
2. Pin Outputs are the result of OR'ing the output states of the cogs together. A cog's output state consists of the bits of its I/O modules (the Counters, the Video Generator, and the I/O Output Register) OR'd together then AND'd with the bits of its Direction Register.
In essence, each I/O pin’s direction and output state is the “wired-OR” of the entire cog collective. This allows the cogs to access and influence the I/O pins simultaneously without the need for any resource arbiter and without any possibility of electrical contention between the cogs.
The result of this I/O pin wiring configuration can easily be described in the following simple rules:
A. A pin is an input only if no active cog sets it to an output.
B. A pin outputs low only if all active cogs that set it to output also set it to low.
C. A pin outputs high if any active cog sets it to an output and also sets it high.
@JonnyMac said:
Given you're at the LSB end of outb and always want to write eight bits, it seems like this might be the way to go (it works in when tested inline with Spin2).
void write3239(uint8_t bits)
{
PASM(
" andn outb, #$FF ' clear p32..p39 \n"
" or outb, r2 ' write to p32..p39 \n"
" or dirb, #$FF ' set to outputs \n"
);
}
Note: I could never get productive with Catalina so I have it, but don't use it. The first parameter passed seems to be in r2 based on Ross's update of my code (above) and examples I've found. BTW, look for .s files in the Catalina folder; they seem to hold function source code..
Some people prefer Spin. I prefer C
Yes, your code is correct - in Catalina, up to 4 function parameters are passed in registers, using local registers r2 .. r5 (if there are more than 4 parameters they are passed on the stack) - but it starts from the right. So when you wrap an inline PASM call in a function, such as func(int a, int b, int c, int d), it would result in d being passed in r2, c in r3, b in r4 and a in r5. Local registers r0 and r1 can be used as scratch registers, and to return a value put it in r0 before exiting the function:
// this function returns a+b+c+d ...
int func(int a, int b, inc c, int d) {
return PASM( // note the 'return' here to return r0
" mov r0, r2\n" // r2 = d
" add r0, r3\n" // r3 = c
" add r0, r4\n" // r4 = b
" add r0, r5\n" // r5 = a
);
}
The .s files are the compiled output of Catalina (which is actually just PASM). The sources are in /source/lib - either .c for C sources, or .e for PASM sources.
The P2 has Assembler instructions to set a byte of a 32bit register (OUTB here) without affecting the other bits. So this may be a fast way (untested):
Thanks for the reminder, Andy. I plugged that into my inline PASM and it works as expected/intended. I tend to be a little verbose (e.g., writing to dirb in that code) so that routines can be atomic.
OK I figured it out and thanks to you all for saving the day once again
It turns out that it DOES matter where you set up the variables etc. I had it initialized in another cog and not the intended one. One question though, is there any way I can access the outputs from another cog by way of a variable of some sort and not by changing the outputs directly per se?
This whole multi-processor thing is taking some time for me to get used to, unfortunately. I'm sure as I work with it more it becomes second nature but right now, I struggle with the dumbest things like OUTPUTS for instance lol... I feel like a real idiot sometimes doing this.
@enorton said:
OK I figured it out and thanks to you all for saving the day once again
It turns out that it DOES matter where you set up the variables etc. I had it initialized in another cog and not the intended one. One question though, is there any way I can access the outputs from another cog by way of a variable of some sort and not by changing the outputs directly per se?
Not exactly sure what you want, but it would be easy enough to set up a global variable and then have all writes to the outputs use a function that updated both the outputs and the variable.
@enorton said:
This whole multi-processor thing is taking some time for me to get used to, unfortunately. I'm sure as I work with it more it becomes second nature but right now, I struggle with the dumbest things like OUTPUTS for instance lol... I feel like a real idiot sometimes doing this.
The Propeller makes all of us look like idiots sometimes!
@enorton said:
OK I figured it out and thanks to you all for saving the day once again
It turns out that it DOES matter where you set up the variables etc. I had it initialized in another cog and not the intended one. One question though, is there any way I can access the outputs from another cog by way of a variable of some sort and not by changing the outputs directly per se?
Not exactly sure what you want, but it would be easy enough to set up a global variable and then have all writes to the outputs use a function that updated both the outputs and the variable.
Ross.
Hmm very interesting
I will give this some thought. Btw the basic functionality is working pretty good now. Just need the updates from you, fix a few issues and port the rest of the code over.
@enorton said:
This whole multi-processor thing is taking some time for me to get used to, unfortunately. I'm sure as I work with it more it becomes second nature but right now, I struggle with the dumbest things like OUTPUTS for instance lol... I feel like a real idiot sometimes doing this.
The Propeller makes all of us look like idiots sometimes!
It's pretty confusing that's for sure. Some days I'm working great and think this really isn't bad at all and then all the sudden nope. It's a fun chip to work with so far. Thank you all very much for helping me out. It is greatly appreciated
Note that this is a Windows only release, intended to give you a preview of the new functionality, and it has not been extensively tested. Install it to a different directory than Catalina 5.8 (by default it will install to "Catalina_5.9 PRE_RELEASE BETA 1") in case you need to revert (note that to swap between installed versions you must change the LCCDIR environment variable - simply selecting other installed versions on the Start Menu is not sufficient).
Here is the relevant extract from the README.TXT:
New Functionality
-----------------
1. The multiport serial libraries (serial2, serial4, serial8) have each had two
new functions added:
int sX_txcount(unsigned port)
int sX_rxcount(unsigned port)
where X = 2, 4 or 8. The functions return the current count of characters
waiting in the transmit or receive buffers.
Other Changes
-------------
1. The Catalina Propeller 2 Reference Manual said the 8 port serial functions
s8_openport() and s8_closeport() returned an int. In fact, they both return
a void - i.e. they don't return anything. The manual has been updated.
2. The Catalina maths functions round() and trunc() were incorrectly defined
in catalina_float.h as returning floats - in fact, they both returned long
values. These functions have been retained, but have been renamed as
_round() and _trunc().
Also, these functions were only available when a maths co-processor was
loaded - e.g. if -lma, -lmb or -lmc (P2 only). New software implementation
called lround() and ltrunc() which return longs have been defined so that
they are available when any maths library option is used - i.e. including
the -lm option.
Also, new functions have been added called fround() and ftrunc() which DO
return floats. So now a program that needs round() or trunc() can define
EITHER:
#define round(x) lround(x)
#define trunc(x) ltrunc(x)
OR:
#define round(x) fround(x)
#define trunc(x) ftrunc(x)
OR:
#define round(x) _round(x)
#define trunc(x) _trunc(x)
depending on whether it needs versions that returns longs, versions that
return floats (or doubles - in Catalina doubles are the same as floats,
so if the program expects these functions to return doubles, it will work
perfectly well with the new versions) or it wants to retain the original
versions.
3. Catalina's original implementation of trunc(), which was also used when
a float was "cast" to an integer, was based on Cam Thompson's original
Float32_A co-processor, which unnecessarily limited the range in which
it would return a value. That range has been extended to include the
maximum range that can be encoded accurately in a float. Note that
this does not mean all longs in this range can be encoded - the way
IEEE457 floats are implemented means there are "gaps" in the integers
that can be encoded as floats once you exceed the number of bits in the
mantissa. However, within the newly extended range (which corresponds to
the integer range of -2,147,483,583 to 2,147,483,583) the implementation
of both ltrunc() and lround() will now return the correct integer value.
Outside that range they will return zero.
4. The documentation regarding the 8 Port Serial plugin was a little
contradictory regarding the meaning and use of S8_MAX_PORTS. Setting this
determines the maximum number of ports that CAN BE OPENED, not the number
of ports that will be opened automatically. A port will only be opened
automatically if the port number is less than S8_MAX_PORTS, AND it has
pins specified in the range 0 .. 63 in the platform configuration file.
If the port has pins specified outside this range (e.g. as -1) then the
port will not be opened automatically but can be opened manually using
the s8_openport() function. A port number greater or equal to S8_MAX_PORTS
will never be opened. If you want different baud rates or large buffer
sizes, it is recommended to open the ports manually.
5. The accuracy of the various _wait functions (i.e. _waitsec(), _waitms(),
_waitus()) has been improved significantly. Also, the calculations of how
long each unit of time is in clock ticks are now only done on the first
call and on any call where a change in clock frequency is detected, not
on every call as in previous releases. This speeds up the calls, but it
means that the very first call in such cases will be very slightly longer
than subsequent calls - if this is a problem, add a call like:
_waitus(0);
at the start of the program to calculate the waits for the current
clock frequency, and all subsequent waits will be more accurate. Note
that any call calculates the times for all the _wait functions, not just
the one actually called. Also note that for _waitus() there is a minimum
number of milliseconds that can be waited for accurately - especially on
the Propeller 1. The actual value depends on the memory model used, but
for Propeller 2 NATIVE it is less than 10us. If shorter accurate wait
times are required, consider using an inline PASM assembly language
function instead of the C _wait functions.
On the Propeller 1, these functions use the WAITCNT instruction, and are
"thread-safe", but on the Propeller 2 they use timer 2 and the WAITCT2
instruction. This means they are not "thread-safe" since waiting on a
timer also stalls interrupts. However, there are also "interrupt-safe"
versions provided for the Propeller 2, called _iwaitsec(), _iwaitms()
and _iwaitus(). These use the POLLCT2 instruction and so do not stall
interrupts, but they busy-wait. This means they consume more power, and
they will also be very slightly less accurate, but accuracy is never
guaranteed in a multi-threaded program, or one that uses interrupts.
Note that this is a Windows only release, intended to give you a preview of the new functionality, and it has not been extensively tested. Install it to a different directory than Catalina 5.8 (by default it will install to "Catalina_5.9 PRE_RELEASE BETA 1") in case you need to revert (note that to swap between installed versions you must change the LCCDIR environment variable - simply selecting other installed versions on the Start Menu is not sufficient).
Here is the relevant extract from the README.TXT:
New Functionality
-----------------
1. The multiport serial libraries (serial2, serial4, serial8) have each had two
new functions added:
int sX_txcount(unsigned port)
int sX_rxcount(unsigned port)
where X = 2, 4 or 8. The functions return the current count of characters
waiting in the transmit or receive buffers.
Other Changes
-------------
1. The Catalina Propeller 2 Reference Manual said the 8 port serial functions
s8_openport() and s8_closeport() returned an int. In fact, they both return
a void - i.e. they don't return anything. The manual has been updated.
2. The Catalina maths functions round() and trunc() were incorrectly defined
in catalina_float.h as returning floats - in fact, they both returned long
values. These functions have been retained, but have been renamed as
_round() and _trunc().
Also, these functions were only available when a maths co-processor was
loaded - e.g. if -lma, -lmb or -lmc (P2 only). New software implementation
called lround() and ltrunc() which return longs have been defined so that
they are available when any maths library option is used - i.e. including
the -lm option.
Also, new functions have been added called fround() and ftrunc() which DO
return floats. So now a program that needs round() or trunc() can define
EITHER:
#define round(x) lround(x)
#define trunc(x) ltrunc(x)
OR:
#define round(x) fround(x)
#define trunc(x) ftrunc(x)
OR:
#define round(x) _round(x)
#define trunc(x) _trunc(x)
depending on whether it needs versions that returns longs, versions that
return floats (or doubles - in Catalina doubles are the same as floats,
so if the program expects these functions to return doubles, it will work
perfectly well with the new versions) or it wants to retain the original
versions.
3. Catalina's original implementation of trunc(), which was also used when
a float was "cast" to an integer, was based on Cam Thompson's original
Float32_A co-processor, which unnecessarily limited the range in which
it would return a value. That range has been extended to include the
maximum range that can be encoded accurately in a float. Note that
this does not mean all longs in this range can be encoded - the way
IEEE457 floats are implemented means there are "gaps" in the integers
that can be encoded as floats once you exceed the number of bits in the
mantissa. However, within the newly extended range (which corresponds to
the integer range of -2,147,483,583 to 2,147,483,583) the implementation
of both ltrunc() and lround() will now return the correct integer value.
Outside that range they will return zero.
4. The documentation regarding the 8 Port Serial plugin was a little
contradictory regarding the meaning and use of S8_MAX_PORTS. Setting this
determines the maximum number of ports that CAN BE OPENED, not the number
of ports that will be opened automatically. A port will only be opened
automatically if the port number is less than S8_MAX_PORTS, AND it has
pins specified in the range 0 .. 63 in the platform configuration file.
If the port has pins specified outside this range (e.g. as -1) then the
port will not be opened automatically but can be opened manually using
the s8_openport() function. A port number greater or equal to S8_MAX_PORTS
will never be opened. If you want different baud rates or large buffer
sizes, it is recommended to open the ports manually.
5. The accuracy of the various _wait functions (i.e. _waitsec(), _waitms(),
_waitus()) has been improved significantly. Also, the calculations of how
long each unit of time is in clock ticks are now only done on the first
call and on any call where a change in clock frequency is detected, not
on every call as in previous releases. This speeds up the calls, but it
means that the very first call in such cases will be very slightly longer
than subsequent calls - if this is a problem, add a call like:
_waitus(0);
at the start of the program to calculate the waits for the current
clock frequency, and all subsequent waits will be more accurate. Note
that any call calculates the times for all the _wait functions, not just
the one actually called. Also note that for _waitus() there is a minimum
number of milliseconds that can be waited for accurately - especially on
the Propeller 1. The actual value depends on the memory model used, but
for Propeller 2 NATIVE it is less than 10us. If shorter accurate wait
times are required, consider using an inline PASM assembly language
function instead of the C _wait functions.
On the Propeller 1, these functions use the WAITCNT instruction, and are
"thread-safe", but on the Propeller 2 they use timer 2 and the WAITCT2
instruction. This means they are not "thread-safe" since waiting on a
timer also stalls interrupts. However, there are also "interrupt-safe"
versions provided for the Propeller 2, called _iwaitsec(), _iwaitms()
and _iwaitus(). These use the POLLCT2 instruction and so do not stall
interrupts, but they busy-wait. This means they consume more power, and
they will also be very slightly less accurate, but accuracy is never
guaranteed in a multi-threaded program, or one that uses interrupts.
Ross.
Thank you Ross. I will give it a whirl soon after I get this annoying small issue figure out
Note that this is a Windows only release, intended to give you a preview of the new functionality, and it has not been extensively tested. Install it to a different directory than Catalina 5.8 (by default it will install to "Catalina_5.9 PRE_RELEASE BETA 1") in case you need to revert (note that to swap between installed versions you must change the LCCDIR environment variable - simply selecting other installed versions on the Start Menu is not sufficient).
Here is the relevant extract from the README.TXT:
New Functionality
-----------------
1. The multiport serial libraries (serial2, serial4, serial8) have each had two
new functions added:
int sX_txcount(unsigned port)
int sX_rxcount(unsigned port)
where X = 2, 4 or 8. The functions return the current count of characters
waiting in the transmit or receive buffers.
Other Changes
-------------
1. The Catalina Propeller 2 Reference Manual said the 8 port serial functions
s8_openport() and s8_closeport() returned an int. In fact, they both return
a void - i.e. they don't return anything. The manual has been updated.
2. The Catalina maths functions round() and trunc() were incorrectly defined
in catalina_float.h as returning floats - in fact, they both returned long
values. These functions have been retained, but have been renamed as
_round() and _trunc().
Also, these functions were only available when a maths co-processor was
loaded - e.g. if -lma, -lmb or -lmc (P2 only). New software implementation
called lround() and ltrunc() which return longs have been defined so that
they are available when any maths library option is used - i.e. including
the -lm option.
Also, new functions have been added called fround() and ftrunc() which DO
return floats. So now a program that needs round() or trunc() can define
EITHER:
#define round(x) lround(x)
#define trunc(x) ltrunc(x)
OR:
#define round(x) fround(x)
#define trunc(x) ftrunc(x)
OR:
#define round(x) _round(x)
#define trunc(x) _trunc(x)
depending on whether it needs versions that returns longs, versions that
return floats (or doubles - in Catalina doubles are the same as floats,
so if the program expects these functions to return doubles, it will work
perfectly well with the new versions) or it wants to retain the original
versions.
3. Catalina's original implementation of trunc(), which was also used when
a float was "cast" to an integer, was based on Cam Thompson's original
Float32_A co-processor, which unnecessarily limited the range in which
it would return a value. That range has been extended to include the
maximum range that can be encoded accurately in a float. Note that
this does not mean all longs in this range can be encoded - the way
IEEE457 floats are implemented means there are "gaps" in the integers
that can be encoded as floats once you exceed the number of bits in the
mantissa. However, within the newly extended range (which corresponds to
the integer range of -2,147,483,583 to 2,147,483,583) the implementation
of both ltrunc() and lround() will now return the correct integer value.
Outside that range they will return zero.
4. The documentation regarding the 8 Port Serial plugin was a little
contradictory regarding the meaning and use of S8_MAX_PORTS. Setting this
determines the maximum number of ports that CAN BE OPENED, not the number
of ports that will be opened automatically. A port will only be opened
automatically if the port number is less than S8_MAX_PORTS, AND it has
pins specified in the range 0 .. 63 in the platform configuration file.
If the port has pins specified outside this range (e.g. as -1) then the
port will not be opened automatically but can be opened manually using
the s8_openport() function. A port number greater or equal to S8_MAX_PORTS
will never be opened. If you want different baud rates or large buffer
sizes, it is recommended to open the ports manually.
5. The accuracy of the various _wait functions (i.e. _waitsec(), _waitms(),
_waitus()) has been improved significantly. Also, the calculations of how
long each unit of time is in clock ticks are now only done on the first
call and on any call where a change in clock frequency is detected, not
on every call as in previous releases. This speeds up the calls, but it
means that the very first call in such cases will be very slightly longer
than subsequent calls - if this is a problem, add a call like:
_waitus(0);
at the start of the program to calculate the waits for the current
clock frequency, and all subsequent waits will be more accurate. Note
that any call calculates the times for all the _wait functions, not just
the one actually called. Also note that for _waitus() there is a minimum
number of milliseconds that can be waited for accurately - especially on
the Propeller 1. The actual value depends on the memory model used, but
for Propeller 2 NATIVE it is less than 10us. If shorter accurate wait
times are required, consider using an inline PASM assembly language
function instead of the C _wait functions.
On the Propeller 1, these functions use the WAITCNT instruction, and are
"thread-safe", but on the Propeller 2 they use timer 2 and the WAITCT2
instruction. This means they are not "thread-safe" since waiting on a
timer also stalls interrupts. However, there are also "interrupt-safe"
versions provided for the Propeller 2, called _iwaitsec(), _iwaitms()
and _iwaitus(). These use the POLLCT2 instruction and so do not stall
interrupts, but they busy-wait. This means they consume more power, and
they will also be very slightly less accurate, but accuracy is never
guaranteed in a multi-threaded program, or one that uses interrupts.
Ross.
Hi Ross,
I have installed the Catalina 5.9 beta release and I have uploaded the code to the chip. It connects as it normally does which is good but noticed the buffer used is always showing 1. Not sure why. I will check into this more and see what is going on. I checked in the P2_CUSTOM file and cannot for the life of me see where I can set the UART buffer sizes. I am using the 8-port serial port driver with 4 active UART ports and the rest disabled.
I also tried the lround() and ltrunc() functions and those seem to work which is good. It's getting late and have yet to try the _wait (delay) stuff. I will dive into all of this in the morning. Thanks for all your help with this. I know you are pretty busy so I will try to do as much testing as I can and hopefully not bother you too much
I have installed the Catalina 5.9 beta release and I have uploaded the code to the chip. It connects as it normally does which is good but noticed the buffer used is always showing 1. Not sure why.
Are you sure that is wrong? I wrote a test program that fills the send buffer with a long strings until it cannot fit any more in and then checks the s8_txcount and it does indeed show more than one 1 character waiting to be sent.
Similarly, the program checks for received characters only after it has done the above processing and it does indeed see the s8_rxcount go higher than 1 if more characters have been received in the meantime. But if your program is sending characters one by one and is processing received characters as they arrive, then perhaps these counts never do get higher than 1.
The test program is in demos\serial8\test_serial8_count.c
I will check into this more and see what is going on. I checked in the P2_CUSTOM file and cannot for the life of me see where I can set the UART buffer sizes. I am using the 8-port serial port driver with 4 active UART ports and the rest disabled.
See the test program for this as well - the buffer sizes are not set in the platform file. By default, the buffer size for all the ports that are auto-opened using the 8 port serial library is 64 bytes for both transmit and receive buffers. This is hard coded in the serial8 library - see source\lib\catalina_serial8\s8_core.c - and changing this default requires recompiling the library. But you don't need to do that - the test program also shows how to close a port (if it has been auto-opened) and then re-open it to use any buffer size you want (the test program uses 512 byte buffers).
I also tried the lround() and ltrunc() functions and those seem to work which is good. It's getting late and have yet to try the _wait (delay) stuff. I will dive into all of this in the morning. Thanks for all your help with this. I know you are pretty busy so I will try to do as much testing as I can and hopefully not bother you too much
No worries. When you get time. There is a test program for the wait functions in demos\examples\ex_wait.c
I have installed the Catalina 5.9 beta release and I have uploaded the code to the chip. It connects as it normally does which is good but noticed the buffer used is always showing 1. Not sure why.
Are you sure that is wrong? I wrote a test program that fills the send buffer with a long strings until it cannot fit any more in and then checks the s8_txcount and it does indeed show more than one 1 character waiting to be sent.
Similarly, the program checks for received characters only after it has done the above processing and it does indeed see the s8_rxcount go higher than 1 if more characters have been received in the meantime. But if your program is sending characters one by one and is processing received characters as they arrive, then perhaps these counts never do get higher than 1.
The test program is in demos\serial8\test_serial8_count.c
I will check into this more and see what is going on. I checked in the P2_CUSTOM file and cannot for the life of me see where I can set the UART buffer sizes. I am using the 8-port serial port driver with 4 active UART ports and the rest disabled.
See the test program for this as well - the buffer sizes are not set in the platform file. By default, the buffer size for all the ports that are auto-opened using the 8 port serial library is 64 bytes for both transmit and receive buffers. This is hard coded in the serial8 library - see source\lib\catalina_serial8\s8_core.c - and changing this default requires recompiling the library. But you don't need to do that - the test program also shows how to close a port (if it has been auto-opened) and then re-open it to use any buffer size you want (the test program uses 512 byte buffers).
I also tried the lround() and ltrunc() functions and those seem to work which is good. It's getting late and have yet to try the _wait (delay) stuff. I will dive into all of this in the morning. Thanks for all your help with this. I know you are pretty busy so I will try to do as much testing as I can and hopefully not bother you too much
No worries. When you get time. There is a test program for the wait functions in demos\examples\ex_wait.c
Ross.
I just tested one of my products and the buffer function shows the maximum buffer size and when the buffer is used it subtracts from it. The way you have your buffers set up is I assume increments by how many are sent or available and the same for receive buffer. Is this correct? I had to build some boards today and have not been able to devote time to development today. I may get back on the project tomorrow afternoon and will take a closer look at how all of this works and report back to you.
I just tested one of my products and the buffer function shows the maximum buffer size and when the buffer is used it subtracts from it. The way you have your buffers set up is I assume increments by how many are sent or available and the same for receive buffer. Is this correct? I had to build some boards today and have not been able to devote time to development today. I may get back on the project tomorrow afternoon and will take a closer look at how all of this works and report back to you.
What you describe is true of the s8_txcheck() function for the tx buffer (but note that s8_rxcheck() does not implement the corresponding function for the rx buffer - it does not return a count, it returns either -1 or the next character in the rx buffer).
The new functions are s8_txcount() and s8_rxcount(), which return the number of characters in the respective buffer i.e. from 0 to the buffer length - 1.
For example, the ex_wait.c test program fills the tx buffer, then fetches the value of s8_txcount() after a wait of a few milliseconds, so you will see this value change if you change the value of the _waitms() function call (which is 5 by default) which allows more or less time for characters to be sent. For example, here are the values I see for various wait times:
To see the value of s8_rxcount() change, simply press a few keys faster than the test program prints them, and the rx count will keep rising, then fall again when you stop pressing keys. It should never go higher than the buffer size even if you just hold a key down forever, but I just noticed while writing this answer that it wraps back to zero, which is a bug!
Comments
How do I do a pin group with _pinw()? I saw this from another thread: pingroup := basepin ADDPINS count
is ADDPINS defined somewhere? How would I write this in c? I need to control 8 bits from pin 32 to 39. Or any group of 8 bits...
I also saw this example:
pingroup := 56 addpins 3
pinwrite(pingroup, %0101)
repeat
waitms(250)
pintoggle(pingroup)
The addpins again is the missing link here.
I don't think there is a function like that in C.
Mike
The Spin2 addpins feature works like this:
pingroup = LSB | ((MSB-LSB) << 6)
I don't know how inline assembly works in Catalina. If it's available, one could borrow the code from the Spin2 interpreter. This is from the interpreter moved to inline PASM in Spin2
Works for me on a P2 EDGE with a breakout board. I tried several different groups of 8 pins and it works on both port A and B.
What board and pins are you using specifically?
Ross.
Here is JonnyMac's code in Catalina inline PASM:
NOTE: I have no idea what this does and have not tested it!
NOTE 2: The above PASM is only for NATIVE mode - the syntax of PASM is different in other modes (e.g. COMPACT, LARGE). So I have added a #error statement to warn about this.
Ross.
It writes value to one or more outputs pins -- though the group must be confined to OUTA or OUTB. The lower six bits of pingroup is the LSB, and bits 6..10 determine how many additional (contiguous) pins are part of the group.
Ok, thanks. Should work ok in Catalina.
****Ok here is what I am trying to do:****
uint8_t drive_port;
// Direction Bits
drive_port = ((drive_port & ~DIR_MASK) | (st.dir_outbits & DIR_MASK));
_OUTB = drive_port;
// Outbits
drive_port = ((drive_port & ~STEP_MASK) | st.step_outbits);
_OUTB = drive_port;
After some delay, I have yet to implement:
drive_port = ((drive_port & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK));
_OUTB = drive_port;
This works on another microcontroller and the function they have is:
/**
* @brief Set GPIO Port OUT Data
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD, PE, PF, PG or PH.
* @param[in] u32Data GPIO port data.
*
* @return None
*
* @details Set the Data into specified GPIO port.
* \hideinitializer
*/
define GPIO_SET_OUT_DATA(port, u32Data) ((port)->DOUT = (u32Data))
The other microcontroller I call this:
GPIO_SET_OUT_DATA(PB, drive_port);
As you can see it is pretty similar to the Propeller 2 by sending the data to the 32-bit pins output register. The way I have done it with the other microcontroller works fantastic and with the Propeller 2 it isn't working.
I wonder if I have _pinh() and _pinl() functions active would they overwrite the OUTA and OUTB writes? I have eeprom and two other I2C devices on P0 - P5 and I have serial ports on P48 - P55. Just curious if those pins are active would they overwrite the 8 bits data trying to go out?
I can confirm that the "drive_port" bits toggle when commanded through a debug serial connection I set up.
It would be better if you posted actual code. For instance, what is "_OUTB"?
If you are using the same pins, then that seems very likely. Try testing with pins that are not used for other purposes.
Ross.
I am using pins 32 to 39 for the 8-bit output port. These pins are dedicated to outputting the 8-bits data only and not used for any other function.
Where can I find the functions for _pinh(), pinl() etc? When calling these functions do, they also write to OUTA or OUTB registers? When I do something like this:
_DIRB |= 0x000000FF;
_OUTB = 0x000000FF;
Then all eight outputs turn on but this is called when the chip initializes. When used in the code I attached earlier I do not see the outputs pulsing...
I have the P2 EVAL board. Pins 32 to 39 are the outputs I am trying to write to.
Given you're at the LSB end of outb and always want to write eight bits, it seems like this might be the way to go (it works in when tested inline with Spin2).
Note: I could never get productive with Catalina so I have it, but don't use it. The first parameter passed seems to be in r2 based on Ross's update of my code (above) and examples I've found. BTW, look for .s files in the Catalina folder; they seem to hold function source code..
You can't do OUTB = 0xff, This will set all the 32 pins to that state IE, 32 - 40 will be high and 41 - 63 low.
Also unlike STM, once a cog accesses a pin that pin is owned by that cog and no other cog can make use of those pins.
Mike
My bad - I had forgotten that I had agreed with the other C compiler makers that on the P2 we would use _DIRA etc, not DIRA. Actually, if you include both <propeller.h> and <propeller2.h> you can use either or both in Catalina. But that's not the issue.
I suspect your problem is actually that initialization code, or some similar code elsewhere. If you set an output 'high' in one cog, you cannot then set it 'low' from another. The logic of how pins are combined is described quite well in the Propeller 1 documentation - I could not find the equivalent description in the Propeller 2 documentation, but it would be similar:
Ross.
Some people prefer Spin. I prefer C
Yes, your code is correct - in Catalina, up to 4 function parameters are passed in registers, using local registers r2 .. r5 (if there are more than 4 parameters they are passed on the stack) - but it starts from the right. So when you wrap an inline PASM call in a function, such as func(int a, int b, int c, int d), it would result in d being passed in r2, c in r3, b in r4 and a in r5. Local registers r0 and r1 can be used as scratch registers, and to return a value put it in r0 before exiting the function:
The .s files are the compiled output of Catalina (which is actually just PASM). The sources are in /source/lib - either .c for C sources, or .e for PASM sources.
The P2 has Assembler instructions to set a byte of a 32bit register (OUTB here) without affecting the other bits. So this may be a fast way (untested):
You don't need to set the direction bits each time you write a new value, just do it once when the direction needs to change.
Andy
Thanks for the reminder, Andy. I plugged that into my inline PASM and it works as expected/intended. I tend to be a little verbose (e.g., writing to dirb in that code) so that routines can be atomic.
OK I figured it out and thanks to you all for saving the day once again
It turns out that it DOES matter where you set up the variables etc. I had it initialized in another cog and not the intended one. One question though, is there any way I can access the outputs from another cog by way of a variable of some sort and not by changing the outputs directly per se?
This whole multi-processor thing is taking some time for me to get used to, unfortunately. I'm sure as I work with it more it becomes second nature but right now, I struggle with the dumbest things like OUTPUTS for instance lol... I feel like a real idiot sometimes doing this.
Not exactly sure what you want, but it would be easy enough to set up a global variable and then have all writes to the outputs use a function that updated both the outputs and the variable.
Ross.
The Propeller makes all of us look like idiots sometimes!
Hmm very interesting
I will give this some thought. Btw the basic functionality is working pretty good now. Just need the updates from you, fix a few issues and port the rest of the code over.
It's pretty confusing that's for sure. Some days I'm working great and think this really isn't bad at all and then all the sudden nope. It's a fun chip to work with so far. Thank you all very much for helping me out. It is greatly appreciated
I have uploaded a beta pre-release of 5.9 here
Note that this is a Windows only release, intended to give you a preview of the new functionality, and it has not been extensively tested. Install it to a different directory than Catalina 5.8 (by default it will install to "Catalina_5.9 PRE_RELEASE BETA 1") in case you need to revert (note that to swap between installed versions you must change the LCCDIR environment variable - simply selecting other installed versions on the Start Menu is not sufficient).
Here is the relevant extract from the README.TXT:
Ross.
Thank you Ross. I will give it a whirl soon after I get this annoying small issue figure out
Hi Ross,
I have installed the Catalina 5.9 beta release and I have uploaded the code to the chip. It connects as it normally does which is good but noticed the buffer used is always showing 1. Not sure why. I will check into this more and see what is going on. I checked in the P2_CUSTOM file and cannot for the life of me see where I can set the UART buffer sizes. I am using the 8-port serial port driver with 4 active UART ports and the rest disabled.
I also tried the lround() and ltrunc() functions and those seem to work which is good. It's getting late and have yet to try the _wait (delay) stuff. I will dive into all of this in the morning. Thanks for all your help with this. I know you are pretty busy so I will try to do as much testing as I can and hopefully not bother you too much
Are you sure that is wrong? I wrote a test program that fills the send buffer with a long strings until it cannot fit any more in and then checks the s8_txcount and it does indeed show more than one 1 character waiting to be sent.
Similarly, the program checks for received characters only after it has done the above processing and it does indeed see the s8_rxcount go higher than 1 if more characters have been received in the meantime. But if your program is sending characters one by one and is processing received characters as they arrive, then perhaps these counts never do get higher than 1.
The test program is in demos\serial8\test_serial8_count.c
See the test program for this as well - the buffer sizes are not set in the platform file. By default, the buffer size for all the ports that are auto-opened using the 8 port serial library is 64 bytes for both transmit and receive buffers. This is hard coded in the serial8 library - see source\lib\catalina_serial8\s8_core.c - and changing this default requires recompiling the library. But you don't need to do that - the test program also shows how to close a port (if it has been auto-opened) and then re-open it to use any buffer size you want (the test program uses 512 byte buffers).
No worries. When you get time. There is a test program for the wait functions in demos\examples\ex_wait.c
Ross.
I just tested one of my products and the buffer function shows the maximum buffer size and when the buffer is used it subtracts from it. The way you have your buffers set up is I assume increments by how many are sent or available and the same for receive buffer. Is this correct? I had to build some boards today and have not been able to devote time to development today. I may get back on the project tomorrow afternoon and will take a closer look at how all of this works and report back to you.
What you describe is true of the s8_txcheck() function for the tx buffer (but note that s8_rxcheck() does not implement the corresponding function for the rx buffer - it does not return a count, it returns either -1 or the next character in the rx buffer).
The new functions are s8_txcount() and s8_rxcount(), which return the number of characters in the respective buffer i.e. from 0 to the buffer length - 1.
For example, the ex_wait.c test program fills the tx buffer, then fetches the value of s8_txcount() after a wait of a few milliseconds, so you will see this value change if you change the value of the _waitms() function call (which is 5 by default) which allows more or less time for characters to be sent. For example, here are the values I see for various wait times:
To see the value of s8_rxcount() change, simply press a few keys faster than the test program prints them, and the rx count will keep rising, then fall again when you stop pressing keys. It should never go higher than the buffer size even if you just hold a key down forever, but I just noticed while writing this answer that it wraps back to zero, which is a bug!
I will fix that and post a new version soon.
Ross.