Glad to hear you're back online! I've been waiting patiently to hear your thoughts on using extra memory in the SSD1963 for program RAM.
If so, then you really do have something like an old PC with 80 column display of arbitrary font and color and also VGA graphics.
The SSD1963 has 1215 kB of RAM but only needs 900 kB for 640x480xRGB VGA. That leaves 315 kB that I'm hoping you'll tell me can be used for RAM.
Combining this with two SQI flash chips on the same 8-bit bus should make for a very impressive system.
Hey, I just though of a name for this system: "C Monster"
Welcome back Ross, was wondering what happened. I feel your pain lost my laptop amd my wifes died 2 weeks later. Also had a lightning strike after that. Isn't technology wonderful!!!
Sorry for the absence - my computer trashed itself recently
I feel your pain too.
Once you are back in the saddle, I'm hoping we can brainstorm using catalina with a touchscreen. The hardware design has changed multiple times but I think it is getting stable now. We have a 16 bit data bus P0-P15 and to get the next word, toggle one pin on the propeller to increment a chain of 161 counters. Preload the counters via P0-P18 if the value needs to change.
This design gives the fastest transfer to a 320x240 touchscreen and preliminary experiments suggest a refresh in 30ms.
It should also mean that catalina in XMM mode should run faster, though this is kind of moot thanks to your nifty cache option.
Ultimately catalina might end up with a touchscreen plugin, but prior to that, while writing such an object, the xmm catalina kernel will need to go to sleep while a cog transfers data from ram to the touchscreen. Fortunately, that code is already written and it is just a matter of dumping out data (ie an icon) that has previously been loaded from the SD card into an array in C.
So, nothing to do quite yet as the boards are still being made, but hopefully we can get catalina working soon on the touchscreen.
One of the joys of windoze! At least its no longer necessary to clean your computer every 3 mths like I used to do ~15yrs ago. My laptop is giving signs of trouble approaching so I am keeping backups (not that I didnt before).
I am onto the RTC section required for a few projects. Perhaps it is best to describe what I am trying to achieve and then ask for comments and guidance...
1. I have an RTC chip. It is shared with other bus items (like the SD card and SRAM memory) and is on the EEPROM I2C bus. I have working code to access the RTC which is a DS1340C (C = inbuilt xtal). It is very similar to the DS1302 and DS1307.
2. I thought that I would only read the RTC on initialisation, or on a specific request. Likewise, only update it by special request.
3. I would have a cog dedicated to keeping the time (like your RTC plugin) just incrementing seconds using the prop CNT values.
4. I thought I would use a hub memory position (via the registry) where seconds or time or both would be kept updated each second by the RTC Plugin.
5. Our Catalina program could obtain the seconds/time at any time by simply reading the registry value. No need for a request because it will always be updated by the RTC cog in the background.
6. Format of the seconds/time: I thought I would implement a modified FAT16/32 time as follows...
[FONT=Courier][SIZE=2]Year20xx Month Date Hours Minutes Seconds
(00-63) (1-12) (1-31) (00-23) (00-59) (00-59)
000000___0000____00000___00000____000000____000000 [/SIZE][/FONT]
[FONT=Courier][SIZE=2]Above uses year base 2000 providing up to year 2063, and accurate to the second.[/SIZE][/FONT]
[FONT=Courier][SIZE=2]We can update the whole 32bit value at once, so no possibility of reading between a partial update.[/SIZE][/FONT]
[SIZE=2]
[/SIZE]
[FONT=Courier][SIZE=2]Conversion to FAT16/32 file format is simple. Shift >>1 then add 16<<25[/SIZE][/FONT]
[FONT=Courier][SIZE=2](i.e. Shift right 1 place, then add 16 to the year because base is 1984 instead of 2000)
[/SIZE][/FONT]
[FONT=Courier][SIZE=2]Year1984+ Month Date Hours Minutes Seconds*2
(00-127) (1-12) (1-31) (00-23) (00-59) (00-58)
0000000___0000____00000___00000____000000____00000 [/SIZE][/FONT]
[FONT=Courier][SIZE=2]Above FAT16/32, the seconds are only counted every 2 seconds because it is 1 bit short!
This gives years 1984-2111, but note 2100 is not a leap year. The time is held in 1 16bit value and the date in another 16 bit value.[/SIZE][/FONT]
FYI: seconds in 4yrs = 126,230,400. So unsigned 32bits can hold 132 years.
From 1904 to 2096, every 4 years are leap years. So, no need to worry about 100 year leap years.
If we also hold a 32bit value of seconds, I suggest we use a base of 2000. I am unsure if this is necessary as well as the date/time value.
6. It is quite likely that the SD driver could be modified to maintain the clock value in hub between SD usage (Dumb RTC using prop). Lonesock does this in his fsrw routines (using just a seconds counter in hub).
7. If Item 6 method was used (dumb RTC in fsrw), then a dynamic Plugin could be used to read and set a real RTC clock chip.
8. A normal Catalina program could obtain the seconds/time at any time by simply reading the registry value. No need for a request because it will always be updated by the RTC cog in the background.
Any ideas or comments on the best way to implement this???
Ross, quick question for you... I'm working on a couple SSD1963 display controller solutions and wonder if I can use the excess RAM for running C programs...
The SSD1963 has 1,000 kB of RAM but a 4.3" display only needs about 400 kB for a single display buffer. That leaves 600 kB that could be used for other things...
To access anywhere in RAM, you just send about 12 bytes to tell it where you want to read or write from. Then, just toggle the read or write strobe to get or set
data on the data bus.
The data bus can be 8, 16, or 24 bits wide, but I think for the Prop, 8 or 16 bit data bus makes the most sense.
Anyway, the SSD1963 will continue to show image from the display buffer while you read or write program memory, so it's pretty non-invasive.
You just can't update the screen and read/write program memory at the same time...
What do you think? Make any sense?
Hi Rayman,
Sorry for the delay - still rebuilding my machine. My first attempt at rebuilding just Windows without having to reinstall all my other software failed, even though this is supposed to be possible. In the end I gave up and decided just to rebuild from absolute scratch. I don't have a lot of time at the moment, so this is taking me longer than I expected.
Yes, you could do what you are proposing. Having to send 12 bytes or so to set the address would make it slow, but if the SSD1963 has an autoincrement mode (which it does seem to - see the "Read Memory Continue" command), then it could still be reasonably fast in SMALL mode, where only code is stored in XMM RAM - most code execution is linear with occasional jumps. Also, when using the cache it seems you could read a whole cache page in essentially one continuous read operation, which would make it execute at reasonable speed.
I am onto the RTC section required for a few projects. Perhaps it is best to describe what I am trying to achieve and then ask for comments and guidance...
... <snip>
Any ideas or comments on the best way to implement this???
Just posting what I sent you privately, as others may have additional ideas to add ...
I can't see any problem with the approach. It all sounds quite logical. However, if you want to allocate a fixed location in upper Hub RAM you will have to modify some very low level Catalina files. Best to try and avoid this, as you will not be able to share your code with others without also sharing all the modified Catalina files.
Instead, I would suggest allocating this location dynamically as part of the plugin initialization - you can do this when the plugin is loaded (several programs do this already - e.g. see "Command_Line.spin" or "HMI.spin" - the current "Clock.spin" does not do this - but it could easily do so, and then pass the address to the plugin on startup). Then, make one of the services your plugin offers return the location of your allocated memory buffer.
Then from C, you can use a "static" variable which you can initalize on the first call. From then on, you just use the memory location. For instance, assuming "get_time_ptr" is a wrapper function that calls the plugin service to fetch the pointer to your time buffer, your C code to fetch the time would look something like this (or you could hand code it in assembly):
long get_time() {
static long *time_ptr = NULL;
if (time_ptr == NULL) {
time_ptr = get_time_ptr();
}
return *time_ptr;
}
Thanks Ross. I was hoping to use it for Large mode... All reads and writes autoincrement, so that's not a problem.
I was thinking that it wouldn't be much worse than Large mode from SPI RAM. I think you have to do 24 or so bit transfers there to set the address, right?
With this, you'd have to do 12 or so byte transfers (but on a byte-sized bus).
Anyway, if you think Large mode might work at all, I've got another question for you...
Do you see a big advantage for a 16-bit bus over an 8-bit bus? Is it 2X faster?
Actually, I guess a better question is this... If we were trying Large mode and using this as RAM,
Are most reads and writes just one 32 bit long? If that's true, it would seem that an 8-bit bus would be
about the same as a 16-bit bus...
Thanks Ross. I was hoping to use it for Large mode... All reads and writes autoincrement, so that's not a problem.
I was thinking that it wouldn't be much worse than Large mode from SPI RAM. I think you have to do 24 or so bit transfers there to set the address, right?
With this, you'd have to do 12 or so byte transfers (but on a byte-sized bus).
Anyway, if you think Large mode might work at all, I've got another question for you...
Do you see a big advantage for a 16-bit bus over an 8-bit bus? Is it 2X faster?
Actually, I guess a better question is this... If we were trying Large mode and using this as RAM,
Are most reads and writes just one 32 bit long? If that's true, it would seem that an 8-bit bus would be
about the same as a 16-bit bus...
Hi Rayman,
Yes, LARGE mode will work as well - but you'd probably have to use the cache to make it fast enough to be useful. The problem with LARGE mode is that it will interleave largely random data accesses amongst the largely sequential instruction accesses.
No, I see no major advantages of a 16 bit bus - it would make an insignificant difference when the cache is used - and I think you will need to use the cache to get any kind of speed at all. And to answer your specific question - yes, most accesses will be 32 bit - because they will be instruction accesses.
Thanks Ross. Now, I can at least dream about doing this...
Actual implementation would be a challenge though because of the layout... It would need a lot of mapping.
For 4.3" screens, it could be pretty easy. You could use it as 208 pages of up to 864 bytes each.
VGA mode would be a bit more of a challenge... Although, maybe I can push the screen off to the side...
Then, you can have 480 pages of up to 224 bytes each.
You can start your read or write from anywhere in a page. But, unless there's some trick I haven't though of yet, you can only go to the end of the page.
Then, you have to start over at the next page...
I am onto generating my RTC plugin for Catalina...
Any help would be greatly appreciated (I am obviously not a C programmer by these dumb and basic questions)
...\Simple\Catalina_Plugin.spin
In Setup you allocate a block of hub data and get its address.
Can this be done by the cog pasm code instead?
Are there advantages to this way? (i.e. removes spin code vs wastes cog space, but makes dynamic loading better???)
While this plugin is not designed to be dynamically loaded and unloaded...
If we dynamically load and unload, what happens to the freed hub space as we have no heap? (presume it is lost)
I want to implement the following in the plugin...
1. Uses 1 long that is updated dynamically by the pasm cog, counting 1 second intervals (commencing year 2000)
2. Uses 1 long that is updated dynamically by the pasm cog, counting 1 second intervals in my slighltly modified FAT format (described above and in a separate thread)
Both of these can be read at any time by the main catalina program. I need a wrapper function, as Ross described above. It is not clear to me where this goes???
3. Implements a few services. I will describe one...
A call to return the date/time in the stringpointer supplied by the call. The string will be updated to "YYYY/MM/DD HH:MM:SS",0 (19 chars + zero terminator) on return. So the calling format should be something like..
This is what I believe should be the C call routines in my program...
secs = GetSeconds();
GetDateTimeString(long *buffer); 'a date/time string is returned in buffer (buffer must beat least 20 bytes)
I am not sure where this goes (the wrapper function)...
// get the time in seconds
long GetSeconds() {
static long *seconds_ptr = NULL;
if (seconds_ptr == NULL) {
time_ptr = get_seconds_ptr();
}
return *seconds_ptr;
}
// get the formatted date/time into the buffer supplied
long get_datetime_string(long *buffer) {
return void;
}
...\xxxx_plugin.h should contain...
// Service_1 is an example "initialization" service:
extern int Service_1(char *buffer);
...\xxxx_plugin.c should contain... (N is a numeric service number)
#include "xxxx_plugin.h"
#define ZZZ n // the generic plugin has this type
int Service_N(char *buffer) {
// Service N is long request with 1 parameter - a pointer to a string of at least 20bytes in length.
// Returns the formatted date/time in the string
return _long_plugin_request(ZZZ, N, (unsigned long)buffer);
}
I am onto generating my RTC plugin for Catalina...
Any help would be greatly appreciated (I am obviously not a C programmer by these dumb and basic questions)
...\Simple\Catalina_Plugin.spin
In Setup you allocate a block of hub data and get its address.
Can this be done by the cog pasm code instead?
From COG PASM it is not easy - COG PASM has neither any memory management, nor any "built-in" or "standard" way of communicating with the Spin initialization code (one of the great drawbacks of the Propeller, in my opinion). It can be done a little easier from LMM PASM - from this code (which is only executed much later, once the kernel is running) you could allocate the required buffer space from the C "heap". and then pass it to the cog via the registry - but this requires the inclusion of (at least) the code for the C malloc function, and a suitable initialization service to be implemented in the cog itself.
Are there advantages to this way? (i.e. removes spin code vs wastes cog space, but makes dynamic loading better???)
The main advantage is that you don't need to include any memory management functions during startup, and you don't need to pass memory management information to the C startup code (which would complicate the startup process).
The purpose of the much simpler allocation model used in the Spin startup code is for allocating buffers that are essantially "static" instead of "dynamic" - i.e. once allocated they are never de-allocated.
While this plugin is not designed to be dynamically loaded and unloaded...
If we dynamically load and unload, what happens to the freed hub space as we have no heap? (presume it is lost)
It is "lost" in the sense that it will never be used by anything else. If you want dynamic behaviour, then yes - you would be better off loading the plugin, then allocating a buffer for it, then passing the buffer address to it via an initialization service. When you unload the plugin you could retreive the buffer address (or simply remember it), stop the cog, then deallocate the buffer space.
I want to implement the following in the plugin...
1. Uses 1 long that is updated dynamically by the pasm cog, counting 1 second intervals (commencing year 2000)
2. Uses 1 long that is updated dynamically by the pasm cog, counting 1 second intervals in my slighltly modified FAT format (described above and in a separate thread)
Both of these can be read at any time by the main catalina program.
An 8 byte buffer is pre-allocated for each cog and it's address stored in the registry. If you need more buffer space than that, you can allocate a larger buffer in the spin startup code and overwrite the existing registry entry with it - you will lose the 8 bytes already allocated, but this is probably not important. Then you can simply use the first 8 bytes of your larger buffer for normal cog communications, and use the memory after the first 8 bytes for your own purposes. Or (as some plugins do) you could allocate a completely new buffer and then pass the address of the allocated buffer the cog itself via an initialization service implemented in the cog - and also add another service that allows a program to retrieve this buffer address at runtime. Essentially, in this case you are passing responsibility for "remembering" the buffer to the cog itself.
I need a wrapper function, as Ross described above. It is not clear to me where this goes???
3. Implements a few services. I will describe one...
<... snip ...>
I am not sure where this goes (the wrapper function)...
<... snip ...>
You can create your own library of access functions simply by creating a subdirectory in your working directory called something like librtc and add your (compled) access functions to that. Leave the header files in the current working directory, and include them using syntax such as #include "xxxx_plugin.h". Then to include the access functions in librtc in to your program you just add -lrtc to your command line. There are examples of creating a simple library starting on page 9 of the Getting Started with Catalina document.
Alternatively, if you want to make your library accessible to more than one program, you can add your new library to the standard "library" location (e.g in C:\Program Files\Catalina\lib for TINY or SMALL programs, or C:\Program Files\Catalina\lib for LARGE programs) and add the header files to the standard "include" location (e.g. C:\Program Files\Catalina\include). C is a bit peculiar here - if you do that you must refer to the include files using a slightly different syntax - i.e. #include <xxxx_plugin.h> - but that's the only difference.
Ross, I though some more about the SSD1963 memory, and it's even worse than I thought...
The memory isn't really byte addressable, it's addressable in 3-bytes (24-bits) per pixels.
But, what about sharing the 8-bit bus with SRAM or Flash?
You made the nice driver for my Flashpoint memory modules (4-bit wide).
If I put one or maybe 2 of them on this bus, does Catalina already have some mechanism to avoid bus contention?
Ross, I though some more about the SSD1963 memory, and it's even worse than I thought...
The memory isn't really byte addressable, it's addressable in 3-bytes (24-bits) per pixels.
But, what about sharing the 8-bit bus with SRAM or Flash?
You made the nice driver for my Flashpoint memory modules (4-bit wide).
If I put one or maybe 2 of them on this bus, does Catalina already have some mechanism to avoid bus contention?
Hi Rayman,
No, there is no built-in mechanism to avoid contention between two XMM devices. There is a mechanism (enabled by defining the SHARED_XMM flag) to avoid contention between the kernel accessing an XMM device and other plugins accessing other devices that share the same pins, but not between two XMM devices. If the access to the XMM devices is such that accessing one device does not interfere with the other then you'd be ok, but if they may conflict because they share pins then you would have to add suitable contention avoidance code to the existing drivers.
While redesigning the touchscreen board (multiple times) I've been mulling over various forms of memory. The display has two 512k ram chips for ultra fast screen refreshes. However, it may be easier *not* to use this ram for XMM but to use another ram chip. It makes things a lot simpler from the software side as there are no data clashes and no need to shut down the catalina kernel all the time.
I've been thinking about XMM and Catalina and caching. If I can free up three propeller pins I think they can be used for SD ram. I know it is very slow compared with 5 pasm instructions to transfer 16 bits for the display, but with caching, it does not matter so much.
Some ideas for the XMM:
1) 3 prop pins running SPI ram (sram, not flash ram).
2) 3 prop pins talking to HC595 chips and a 512k sram chip and clock data
3) Use the I2C bus P28 P29 and some MCP23016 explander chips to talk to a 512k chip (frees up those 3 prop pins too).
4) Use a combination of MCP23016 chips, 74HC161 clock chips and a 512k ram chip all driven from the I2C bus
Option 1 is very simple, but programs do grow in size and I think those SPI ram chips are only 32k?
Option 2 is simple and old skool
Option 3 should work - is there room inside the catalina XMM cog driver for I2C code?
Option 4 is something that has come up having built a similar circuit for the touchscreen driver. Instead of loading in the new address each time, preload five 161 counters with the address and then it is just one clock pulse to get the next byte. This ought to pair well with caching drivers where all the data is sequential and read in block.
I also like the idea of using the I2C bus as any external ram design can be piggy backed on any existing prop circuit without conflicts. There are a fair few chips but they are chips that are mostly 40c chips. I think it would be one 512k ram chip, two MCP23016 chips and five 161 chips. That is 19 bits and there is a spare bit on the last 161 chip so it could be tempting to use that to drive a second 512k ram chip giving 1 meg of memory.
While redesigning the touchscreen board (multiple times) I've been mulling over various forms of memory. The display has two 512k ram chips for ultra fast screen refreshes. However, it may be easier *not* to use this ram for XMM but to use another ram chip. It makes things a lot simpler from the software side as there are no data clashes and no need to shut down the catalina kernel all the time.
I've been thinking about XMM and Catalina and caching. If I can free up three propeller pins I think they can be used for SD ram. I know it is very slow compared with 5 pasm instructions to transfer 16 bits for the display, but with caching, it does not matter so much.
Some ideas for the XMM:
1) 3 prop pins running SPI ram (sram, not flash ram).
2) 3 prop pins talking to HC595 chips and a 512k sram chip and clock data
3) Use the I2C bus P28 P29 and some MCP23016 explander chips to talk to a 512k chip (frees up those 3 prop pins too).
4) Use a combination of MCP23016 chips, 74HC161 clock chips and a 512k ram chip all driven from the I2C bus
Option 1 is very simple, but programs do grow in size and I think those SPI ram chips are only 32k?
Option 2 is simple and old skool
Option 3 should work - is there room inside the catalina XMM cog driver for I2C code?
Option 4 is something that has come up having built a similar circuit for the touchscreen driver. Instead of loading in the new address each time, preload five 161 counters with the address and then it is just one clock pulse to get the next byte. This ought to pair well with caching drivers where all the data is sequential and read in block.
I also like the idea of using the I2C bus as any external ram design can be piggy backed on any existing prop circuit without conflicts. There are a fair few chips but they are chips that are mostly 40c chips. I think it would be one 512k ram chip, two MCP23016 chips and five 161 chips. That is 19 bits and there is a spare bit on the last 161 chip so it could be tempting to use that to drive a second 512k ram chip giving 1 meg of memory.
Your thoughts would be most appreciated.
Hi Dr_A,
You'd be better off asking someone who knows something about hardware. For me, hardware is just an annoyance you generally have to spend hours programming around and then debugging when it doesn't do what you want
I get option 1 (simple serial RAM), but the others I don't understand. You'd probably need to draw me a circuit diagram so I can see what you mean.
You'd be better off asking someone who knows something about hardware. For me, hardware is just an annoyance you generally have to spend hours programming around and then debugging when it doesn't do what you want
he he that makes me chuckle!
I'll try to draw something up. Off to the shed first. Have to build something to prove the concept. I'll draw a schematic if it works. brb
The default receive buffer in Catalina is only 16 bytes and we were having problems with the buffer being overwritten (115,200 baud). With Ross's help, I located the catalina files and have updated them to permit the buffer to be specified as 4/8/16/32/64/128/256 bytes. We tested with 32 bytes and solved our overwrite problems.
The files are attached. They are both in the TARGET directory of Catalina.
Catalina_PC_Keyboard.spin
Change kb_rxbuffersize = 32 ' rx buffer size(bytes): binary! 16/32/64/128/256
to your required size. This would be better defined in one of the hardware definitions but I will leave that for Ross in v3.5.
The default receive buffer in Catalina is only 16 bytes and we were having problems with the buffer being overwritten (115,200 baud). With Ross's help, I located the catalina files and have updated them to permit the buffer to be specified as 4/8/16/32/64/128/256 bytes. We tested with 32 bytes and solved our overwrite problems.
The files are attached. They are both in the TARGET directory of Catalina.
Thanks Cluso!
I'll include the updated versions in Catalina 3.5, plus instructions on how to modify it if others need to. I'll also add instructions on how to change the baud rate (which is another common question).
I have had several requests for updated library functions for Catalina, and release 3.5 is taking longer than expected. This is mainly because every time I think I have some time to work on it, I find yet more software I need to re-install after my PC crashed and burned - and installing even the most trivial package takes hours under Windows 7 (for some bizarre reason that Microsoft seems unable to explain).
So I thought I'd release a preview of the Catalina 3.5 library changes already implemented, in a form suitable for use with Catalina 3.4. The attached zip file contains both compiled and source versions of all the libraries compiled with Catalina 3.4 (it was easiest just to zip up the whole thing, so that's what I did). Unzip over your existing Catalina directory. Note I have only tested these on Windows - the sources are the same for Linux, but you may have to recompile the libraries from the sources provided.
The changes are minor, but have been requested by several people:
Additional functions to access all the Propeller special registers from C. Also, these routines now don't unnecessarily "toggle" the outputs while updating them. Thanks to Ted Stefanik for these updates.
The capability to create directories in the SD Card file system. This is not an ANSI C function (ANSI C doesn't define this) but it can be used in conjunction with normal ANSI C file access.
Here are some annotated extracts from the library header files:
From catalina_cog.h:
/*
* Propeller Special Register access write functions.
*
* NOTE: in all cases, mask indicates the bits to operate on, and the
* other parameter indicates the new values (only the
* bits corresponding to the mask will be affected).
*/
extern unsigned _dira(unsigned mask, unsigned direction);
extern unsigned _dirb(unsigned mask, unsigned direction);
extern unsigned _outa(unsigned mask, unsigned output);
extern unsigned _outb(unsigned mask, unsigned output);
extern unsigned _ctra(unsigned mask, unsigned control);
extern unsigned _ctrb(unsigned mask, unsigned control);
extern unsigned _frqa(unsigned mask, unsigned frequency);
extern unsigned _frqb(unsigned mask, unsigned frequency);
extern unsigned _phsa(unsigned mask, unsigned phase);
extern unsigned _phsb(unsigned mask, unsigned phase);
extern unsigned _vcfg(unsigned mask, unsigned config);
extern unsigned _vscl(unsigned mask, unsigned scale);
From catalina_fs.h:
/*
* create a new directory. The path to the new directory must already exist
* (i.e. only the last element of the path name is created) and a directory
* must not already exist with that name.
*/
extern int _create_directory(const char *path);
Finally, it is worth pointing out a couple of things that have stumped a few people:
Some people have asked how to change file systems - e.g. if you want to swap SD Cards. There are _mount() and _unmount() functions (documented in catalina_fs.h) - these are not standard ANSI functions, but can be used in conjunction with them. However, mounting is done automatically on the first file access - so really all you need to do is call _unmount().
The path separator is / even though DOSFS is basically a DOS based file system. So to create or access a file called file.txt in subdirectory dir you would use a path name like /dir/file.txt (i.e. not \dir\file.txt).
DOSFS allows you to use characters that would normally be considered invalid in a DOS file system - so if you do accidentally use \ as a path separator and try to create a file with a name like dir\file.txt then you will end up with a file called dir\file.txt in the root directory, rather than a file called file.txt in the dir subdirectory. Such files may be unable to be accessed or managed if you insert the SD card in a DOS or Windows PC.
The DOSFS file system has no concept of a "current" directory, so you must use the full path name. Only the last element of the path name can be affected by a call, so to create a file called /dir1/dir2/file.txt in an empty file system you need to do it in several steps - e.g:
Just tried it, and it works ok. If you are loading from EEPROM, you generally don't have much space to play with the FAT32 file system when you are using stdio calls to access it (i.e. fopen, fread etc) - but you can easily do so using the catalina access functions (which are much smaller!).
I successfully compiled and ran the program test_catalina_fs.c (located in the catalina\demo directory) from EEPROM. This shows DOSFS is working ok on a FAT32 SD card when accessed from a program booted from EEPROM.
Specifically, here is the command I used to compile the program:
As you know I have a plugin that allocates a PluginBlock. The address of that block is passed by a command put into the appropriate REQUEST table and the address of the PluginBlock is passed in the second long of the REQUEST table (the request table is 2 longs for each cog). Once the pasm program retrieves this PluginBlock address (service call) it clears the first Request long to indicate it has taken it (completed the service call).
Now the pasm program knows where the PluginBlock is located. However, the catalina program is still booting, and so will lose the PluginBlock address during this process.
What is the best way to do this? (I looked for a plugin that catalina used that did something like this but couldnt find one)
Pasm could replace the pointer contained in the REGISTRY (lower 24 bits) with the address of the pluginblock, and all should then work, with the first 2 longs of the PluginBlock now being used for commands rather that the REQUEST table. Is this perhaps the way you recommend, or is there another?
As you know I have a plugin that allocates a PluginBlock. The address of that block is passed by a command put into the appropriate REQUEST table and the address of the PluginBlock is passed in the second long of the REQUEST table (the request table is 2 longs for each cog). Once the pasm program retrieves this PluginBlock address (service call) it clears the first Request long to indicate it has taken it (completed the service call).
Now the pasm program knows where the PluginBlock is located. However, the catalina program is still booting, and so will lose the PluginBlock address during this process.
What is the best way to do this? (I looked for a plugin that catalina used that did something like this but couldnt find one)
Pasm could replace the pointer contained in the REGISTRY (lower 24 bits) with the address of the pluginblock, and all should then work, with the first 2 longs of the PluginBlock now being used for commands rather that the REQUEST table. Is this perhaps the way you recommend, or is there another?
Yes, that would work, and would be a perfectly acceptable method - provided you don't intend to make the plugin dynamically loadable/unloadable. Iif you also need that capability, then you would have to ensure the original value in the REGISTRY is restored when the current plugin is unloaded.
Another way is to leave the REGISTRY intact, and have the plugin tell the C program where the allocated memory block is. How you do this depends on how the plugin works. If your plugin does not need to provide specific services to the C program (or the plugin expects to use the PluginBlock for this purpose), then by all means simply leave the PluginBlock address in the second long of the REQUEST block. Catalina will not overwrite this, so the C program can simply pick it up from there whenever it needs it.
If you do intend to use the REQUEST block to request services of the plugin (which is the technique most plugins use) then another approach is to add a specific service to the plugin that returns the PluginBlock address - i.e. when you place a specific (non-zero) request in the first long of the REQUEST block, the plugin should respond by placing the BluginBlock address - which it knows - in the second long, and then clearing the first long. The calling C program waits till the first long is cleared, then reads the second long to get the PluginBlock address.
Hi Ross,
Two discoveries that I recently found...
1. I could not get printf %f to work. Is there some switch I am missing?
2. If a plugin allocates hub ram during the spin initialisation, this is cleared by catalina following this. If you are using Kye's loading in his FAT driver, I have a patch for this.
Hi Ross,
Two discoveries that I recently found...
1. I could not get printf %f to work. Is there some switch I am missing?
2. If a plugin allocates hub ram during the spin initialisation, this is cleared by catalina following this. If you are using Kye's loading in his FAT driver, I have a patch for this.
Hi Ray,
On point 1 - are you compiling with -lc (not -lci)? The stdio functions relating to floating point numbers are one of the major differences between these two versions of the C library. If this is not the problem, send me (or post) your code and I'll have a look.
On point 2, Catalina should not clear Hub RAM allocated by a plugin during Spin initialization - but non-plugin Spin programs will not follow the same memory conventions, and so Catalina may indeed be overwriting their Hub RAM. Send me your code and I'll check. Also, note that the conventions for allocating Hub RAM have changed in Catalina 3.5, so if you have a working method to add non-plugin Spin programs, you may need to modify it when you upgrade to Catalina 3.5.
Thanks Ross.
1. That will be the problem. I declared a float and set it to a float value, then used the printf with %f and %f displayed and not the float value.
2. Will do. The registry and request block remained intact, but the allocated plugin block was cleared. I will re-check with 3.5 when I do the mods.
Comments
If so, then you really do have something like an old PC with 80 column display of arbitrary font and color and also VGA graphics.
The SSD1963 has 1215 kB of RAM but only needs 900 kB for 640x480xRGB VGA. That leaves 315 kB that I'm hoping you'll tell me can be used for RAM.
Combining this with two SQI flash chips on the same 8-bit bus should make for a very impressive system.
Hey, I just though of a name for this system: "C Monster"
I feel your pain too.
Once you are back in the saddle, I'm hoping we can brainstorm using catalina with a touchscreen. The hardware design has changed multiple times but I think it is getting stable now. We have a 16 bit data bus P0-P15 and to get the next word, toggle one pin on the propeller to increment a chain of 161 counters. Preload the counters via P0-P18 if the value needs to change.
This design gives the fastest transfer to a 320x240 touchscreen and preliminary experiments suggest a refresh in 30ms.
It should also mean that catalina in XMM mode should run faster, though this is kind of moot thanks to your nifty cache option.
This is more a note to myself with a link to this thread http://forums.parallax.com/showthread.php?130739-Catalina-3.0/page13 with the discussion about pausing catalina.
Ultimately catalina might end up with a touchscreen plugin, but prior to that, while writing such an object, the xmm catalina kernel will need to go to sleep while a cog transfers data from ram to the touchscreen. Fortunately, that code is already written and it is just a matter of dumping out data (ie an icon) that has previously been loaded from the SD card into an array in C.
So, nothing to do quite yet as the boards are still being made, but hopefully we can get catalina working soon on the touchscreen.
Anyway, nice your back online Ross.
1. I have an RTC chip. It is shared with other bus items (like the SD card and SRAM memory) and is on the EEPROM I2C bus. I have working code to access the RTC which is a DS1340C (C = inbuilt xtal). It is very similar to the DS1302 and DS1307.
2. I thought that I would only read the RTC on initialisation, or on a specific request. Likewise, only update it by special request.
3. I would have a cog dedicated to keeping the time (like your RTC plugin) just incrementing seconds using the prop CNT values.
4. I thought I would use a hub memory position (via the registry) where seconds or time or both would be kept updated each second by the RTC Plugin.
5. Our Catalina program could obtain the seconds/time at any time by simply reading the registry value. No need for a request because it will always be updated by the RTC cog in the background.
6. Format of the seconds/time: I thought I would implement a modified FAT16/32 time as follows...
FYI: seconds in 4yrs = 126,230,400. So unsigned 32bits can hold 132 years.
From 1904 to 2096, every 4 years are leap years. So, no need to worry about 100 year leap years.
If we also hold a 32bit value of seconds, I suggest we use a base of 2000. I am unsure if this is necessary as well as the date/time value.
6. It is quite likely that the SD driver could be modified to maintain the clock value in hub between SD usage (Dumb RTC using prop). Lonesock does this in his fsrw routines (using just a seconds counter in hub).
7. If Item 6 method was used (dumb RTC in fsrw), then a dynamic Plugin could be used to read and set a real RTC clock chip.
8. A normal Catalina program could obtain the seconds/time at any time by simply reading the registry value. No need for a request because it will always be updated by the RTC cog in the background.
Any ideas or comments on the best way to implement this???
Hi Rayman,
Sorry for the delay - still rebuilding my machine. My first attempt at rebuilding just Windows without having to reinstall all my other software failed, even though this is supposed to be possible. In the end I gave up and decided just to rebuild from absolute scratch. I don't have a lot of time at the moment, so this is taking me longer than I expected.
Yes, you could do what you are proposing. Having to send 12 bytes or so to set the address would make it slow, but if the SSD1963 has an autoincrement mode (which it does seem to - see the "Read Memory Continue" command), then it could still be reasonably fast in SMALL mode, where only code is stored in XMM RAM - most code execution is linear with occasional jumps. Also, when using the cache it seems you could read a whole cache page in essentially one continuous read operation, which would make it execute at reasonable speed.
Ross.
Just posting what I sent you privately, as others may have additional ideas to add ...
I can't see any problem with the approach. It all sounds quite logical. However, if you want to allocate a fixed location in upper Hub RAM you will have to modify some very low level Catalina files. Best to try and avoid this, as you will not be able to share your code with others without also sharing all the modified Catalina files.
Instead, I would suggest allocating this location dynamically as part of the plugin initialization - you can do this when the plugin is loaded (several programs do this already - e.g. see "Command_Line.spin" or "HMI.spin" - the current "Clock.spin" does not do this - but it could easily do so, and then pass the address to the plugin on startup). Then, make one of the services your plugin offers return the location of your allocated memory buffer.
Then from C, you can use a "static" variable which you can initalize on the first call. From then on, you just use the memory location. For instance, assuming "get_time_ptr" is a wrapper function that calls the plugin service to fetch the pointer to your time buffer, your C code to fetch the time would look something like this (or you could hand code it in assembly):
Ross.
I was thinking that it wouldn't be much worse than Large mode from SPI RAM. I think you have to do 24 or so bit transfers there to set the address, right?
With this, you'd have to do 12 or so byte transfers (but on a byte-sized bus).
Anyway, if you think Large mode might work at all, I've got another question for you...
Do you see a big advantage for a 16-bit bus over an 8-bit bus? Is it 2X faster?
Actually, I guess a better question is this... If we were trying Large mode and using this as RAM,
Are most reads and writes just one 32 bit long? If that's true, it would seem that an 8-bit bus would be
about the same as a 16-bit bus...
Hi Rayman,
Yes, LARGE mode will work as well - but you'd probably have to use the cache to make it fast enough to be useful. The problem with LARGE mode is that it will interleave largely random data accesses amongst the largely sequential instruction accesses.
No, I see no major advantages of a 16 bit bus - it would make an insignificant difference when the cache is used - and I think you will need to use the cache to get any kind of speed at all. And to answer your specific question - yes, most accesses will be 32 bit - because they will be instruction accesses.
Ross.
Actual implementation would be a challenge though because of the layout... It would need a lot of mapping.
For 4.3" screens, it could be pretty easy. You could use it as 208 pages of up to 864 bytes each.
VGA mode would be a bit more of a challenge... Although, maybe I can push the screen off to the side...
Then, you can have 480 pages of up to 224 bytes each.
You can start your read or write from anywhere in a page. But, unless there's some trick I haven't though of yet, you can only go to the end of the page.
Then, you have to start over at the next page...
Any help would be greatly appreciated (I am obviously not a C programmer by these dumb and basic questions)
...\Simple\Catalina_Plugin.spin
In Setup you allocate a block of hub data and get its address.
Can this be done by the cog pasm code instead?
Are there advantages to this way? (i.e. removes spin code vs wastes cog space, but makes dynamic loading better???)
While this plugin is not designed to be dynamically loaded and unloaded...
If we dynamically load and unload, what happens to the freed hub space as we have no heap? (presume it is lost)
I want to implement the following in the plugin...
1. Uses 1 long that is updated dynamically by the pasm cog, counting 1 second intervals (commencing year 2000)
2. Uses 1 long that is updated dynamically by the pasm cog, counting 1 second intervals in my slighltly modified FAT format (described above and in a separate thread)
Both of these can be read at any time by the main catalina program. I need a wrapper function, as Ross described above. It is not clear to me where this goes???
3. Implements a few services. I will describe one...
A call to return the date/time in the stringpointer supplied by the call. The string will be updated to "YYYY/MM/DD HH:MM:SS",0 (19 chars + zero terminator) on return. So the calling format should be something like..
This is what I believe should be the C call routines in my program...
I am not sure where this goes (the wrapper function)...
...\xxxx_plugin.h should contain... ...\xxxx_plugin.c should contain... (N is a numeric service number)
The purpose of the much simpler allocation model used in the Spin startup code is for allocating buffers that are essantially "static" instead of "dynamic" - i.e. once allocated they are never de-allocated. It is "lost" in the sense that it will never be used by anything else. If you want dynamic behaviour, then yes - you would be better off loading the plugin, then allocating a buffer for it, then passing the buffer address to it via an initialization service. When you unload the plugin you could retreive the buffer address (or simply remember it), stop the cog, then deallocate the buffer space. An 8 byte buffer is pre-allocated for each cog and it's address stored in the registry. If you need more buffer space than that, you can allocate a larger buffer in the spin startup code and overwrite the existing registry entry with it - you will lose the 8 bytes already allocated, but this is probably not important. Then you can simply use the first 8 bytes of your larger buffer for normal cog communications, and use the memory after the first 8 bytes for your own purposes. Or (as some plugins do) you could allocate a completely new buffer and then pass the address of the allocated buffer the cog itself via an initialization service implemented in the cog - and also add another service that allows a program to retrieve this buffer address at runtime. Essentially, in this case you are passing responsibility for "remembering" the buffer to the cog itself.
You can create your own library of access functions simply by creating a subdirectory in your working directory called something like librtc and add your (compled) access functions to that. Leave the header files in the current working directory, and include them using syntax such as #include "xxxx_plugin.h". Then to include the access functions in librtc in to your program you just add -lrtc to your command line. There are examples of creating a simple library starting on page 9 of the Getting Started with Catalina document.
Alternatively, if you want to make your library accessible to more than one program, you can add your new library to the standard "library" location (e.g in C:\Program Files\Catalina\lib for TINY or SMALL programs, or C:\Program Files\Catalina\lib for LARGE programs) and add the header files to the standard "include" location (e.g. C:\Program Files\Catalina\include). C is a bit peculiar here - if you do that you must refer to the include files using a slightly different syntax - i.e. #include <xxxx_plugin.h> - but that's the only difference.
Ross.
The memory isn't really byte addressable, it's addressable in 3-bytes (24-bits) per pixels.
But, what about sharing the 8-bit bus with SRAM or Flash?
You made the nice driver for my Flashpoint memory modules (4-bit wide).
If I put one or maybe 2 of them on this bus, does Catalina already have some mechanism to avoid bus contention?
Hi Rayman,
No, there is no built-in mechanism to avoid contention between two XMM devices. There is a mechanism (enabled by defining the SHARED_XMM flag) to avoid contention between the kernel accessing an XMM device and other plugins accessing other devices that share the same pins, but not between two XMM devices. If the access to the XMM devices is such that accessing one device does not interfere with the other then you'd be ok, but if they may conflict because they share pins then you would have to add suitable contention avoidance code to the existing drivers.
Ross.
While redesigning the touchscreen board (multiple times) I've been mulling over various forms of memory. The display has two 512k ram chips for ultra fast screen refreshes. However, it may be easier *not* to use this ram for XMM but to use another ram chip. It makes things a lot simpler from the software side as there are no data clashes and no need to shut down the catalina kernel all the time.
I've been thinking about XMM and Catalina and caching. If I can free up three propeller pins I think they can be used for SD ram. I know it is very slow compared with 5 pasm instructions to transfer 16 bits for the display, but with caching, it does not matter so much.
Some ideas for the XMM:
1) 3 prop pins running SPI ram (sram, not flash ram).
2) 3 prop pins talking to HC595 chips and a 512k sram chip and clock data
3) Use the I2C bus P28 P29 and some MCP23016 explander chips to talk to a 512k chip (frees up those 3 prop pins too).
4) Use a combination of MCP23016 chips, 74HC161 clock chips and a 512k ram chip all driven from the I2C bus
Option 1 is very simple, but programs do grow in size and I think those SPI ram chips are only 32k?
Option 2 is simple and old skool
Option 3 should work - is there room inside the catalina XMM cog driver for I2C code?
Option 4 is something that has come up having built a similar circuit for the touchscreen driver. Instead of loading in the new address each time, preload five 161 counters with the address and then it is just one clock pulse to get the next byte. This ought to pair well with caching drivers where all the data is sequential and read in block.
I also like the idea of using the I2C bus as any external ram design can be piggy backed on any existing prop circuit without conflicts. There are a fair few chips but they are chips that are mostly 40c chips. I think it would be one 512k ram chip, two MCP23016 chips and five 161 chips. That is 19 bits and there is a spare bit on the last 161 chip so it could be tempting to use that to drive a second 512k ram chip giving 1 meg of memory.
Your thoughts would be most appreciated.
Hi Dr_A,
You'd be better off asking someone who knows something about hardware. For me, hardware is just an annoyance you generally have to spend hours programming around and then debugging when it doesn't do what you want
I get option 1 (simple serial RAM), but the others I don't understand. You'd probably need to draw me a circuit diagram so I can see what you mean.
Ross.
he he that makes me chuckle!
I'll try to draw something up. Off to the shed first. Have to build something to prove the concept. I'll draw a schematic if it works. brb
The default receive buffer in Catalina is only 16 bytes and we were having problems with the buffer being overwritten (115,200 baud). With Ross's help, I located the catalina files and have updated them to permit the buffer to be specified as 4/8/16/32/64/128/256 bytes. We tested with 32 bytes and solved our overwrite problems.
The files are attached. They are both in the TARGET directory of Catalina.
Catalina_PC_Keyboard.spin
Change kb_rxbuffersize = 32 ' rx buffer size(bytes): binary! 16/32/64/128/256
to your required size. This would be better defined in one of the hardware definitions but I will leave that for Ross in v3.5.
Catalina_HMI_Plugin_PC.spin
Catalina_HMI_Plugin_PC.spin
Catalina_PC_Keyboard.spin
Thanks Cluso!
I'll include the updated versions in Catalina 3.5, plus instructions on how to modify it if others need to. I'll also add instructions on how to change the baud rate (which is another common question).
Ross.
I have had several requests for updated library functions for Catalina, and release 3.5 is taking longer than expected. This is mainly because every time I think I have some time to work on it, I find yet more software I need to re-install after my PC crashed and burned - and installing even the most trivial package takes hours under Windows 7 (for some bizarre reason that Microsoft seems unable to explain).
So I thought I'd release a preview of the Catalina 3.5 library changes already implemented, in a form suitable for use with Catalina 3.4. The attached zip file contains both compiled and source versions of all the libraries compiled with Catalina 3.4 (it was easiest just to zip up the whole thing, so that's what I did). Unzip over your existing Catalina directory. Note I have only tested these on Windows - the sources are the same for Linux, but you may have to recompile the libraries from the sources provided.
The changes are minor, but have been requested by several people:
- Additional functions to access all the Propeller special registers from C. Also, these routines now don't unnecessarily "toggle" the outputs while updating them. Thanks to Ted Stefanik for these updates.
- The capability to create directories in the SD Card file system. This is not an ANSI C function (ANSI C doesn't define this) but it can be used in conjunction with normal ANSI C file access.
Here are some annotated extracts from the library header files:From catalina_cog.h:
From catalina_fs.h:
Finally, it is worth pointing out a couple of things that have stumped a few people:
Hi Cluso,
I must admit I haven't used the EEPROM loader for a while - it should work. I'll investigate and let you know.
Ross.
Just tried it, and it works ok. If you are loading from EEPROM, you generally don't have much space to play with the FAT32 file system when you are using stdio calls to access it (i.e. fopen, fread etc) - but you can easily do so using the catalina access functions (which are much smaller!).
I successfully compiled and ran the program test_catalina_fs.c (located in the catalina\demo directory) from EEPROM. This shows DOSFS is working ok on a FAT32 SD card when accessed from a program booted from EEPROM.
Specifically, here is the command I used to compile the program:
I then used the Hydra Asset Manager to load it into EEPROM.
If you let me know more details of the specific configuration you are having problems with, I'll see what I can do.
Ross.
As you know I have a plugin that allocates a PluginBlock. The address of that block is passed by a command put into the appropriate REQUEST table and the address of the PluginBlock is passed in the second long of the REQUEST table (the request table is 2 longs for each cog). Once the pasm program retrieves this PluginBlock address (service call) it clears the first Request long to indicate it has taken it (completed the service call).
Now the pasm program knows where the PluginBlock is located. However, the catalina program is still booting, and so will lose the PluginBlock address during this process.
What is the best way to do this? (I looked for a plugin that catalina used that did something like this but couldnt find one)
Pasm could replace the pointer contained in the REGISTRY (lower 24 bits) with the address of the pluginblock, and all should then work, with the first 2 longs of the PluginBlock now being used for commands rather that the REQUEST table. Is this perhaps the way you recommend, or is there another?
Yes, that would work, and would be a perfectly acceptable method - provided you don't intend to make the plugin dynamically loadable/unloadable. Iif you also need that capability, then you would have to ensure the original value in the REGISTRY is restored when the current plugin is unloaded.
Another way is to leave the REGISTRY intact, and have the plugin tell the C program where the allocated memory block is. How you do this depends on how the plugin works. If your plugin does not need to provide specific services to the C program (or the plugin expects to use the PluginBlock for this purpose), then by all means simply leave the PluginBlock address in the second long of the REQUEST block. Catalina will not overwrite this, so the C program can simply pick it up from there whenever it needs it.
If you do intend to use the REQUEST block to request services of the plugin (which is the technique most plugins use) then another approach is to add a specific service to the plugin that returns the PluginBlock address - i.e. when you place a specific (non-zero) request in the first long of the REQUEST block, the plugin should respond by placing the BluginBlock address - which it knows - in the second long, and then clearing the first long. The calling C program waits till the first long is cleared, then reads the second long to get the PluginBlock address.
Ross.
Catalina 3.5 is now available. See here.
Ross.
Two discoveries that I recently found...
1. I could not get printf %f to work. Is there some switch I am missing?
2. If a plugin allocates hub ram during the spin initialisation, this is cleared by catalina following this. If you are using Kye's loading in his FAT driver, I have a patch for this.
Hi Ray,
On point 1 - are you compiling with -lc (not -lci)? The stdio functions relating to floating point numbers are one of the major differences between these two versions of the C library. If this is not the problem, send me (or post) your code and I'll have a look.
On point 2, Catalina should not clear Hub RAM allocated by a plugin during Spin initialization - but non-plugin Spin programs will not follow the same memory conventions, and so Catalina may indeed be overwriting their Hub RAM. Send me your code and I'll check. Also, note that the conventions for allocating Hub RAM have changed in Catalina 3.5, so if you have a working method to add non-plugin Spin programs, you may need to modify it when you upgrade to Catalina 3.5.
Ross.
1. That will be the problem. I declared a float and set it to a float value, then used the printf with %f and %f displayed and not the float value.
2. Will do. The registry and request block remained intact, but the allocated plugin block was cleared. I will re-check with 3.5 when I do the mods.