Shop OBEX P1 Docs P2 Docs Learn Events
Catalina 3.0 - Page 10 — Parallax Forums

Catalina 3.0

17810121317

Comments

  • RossHRossH Posts: 5,519
    edited 2011-05-04 05:02
    Dr_Acula wrote: »
    ok, compiling on my IDE I get this. I don't know what to do with the batch program and it probably has to be run from a particular directory which has a particular include in it, which may or may not be the same as your include, which may introduce other variables. But here is the error of that C code as it is, compiled with catalina -lcx -D PLUGIN -x5 -M 256k -D DRACBLADE -D HIRES_VGA NEW.C
       ===================
       SETTING UP CATALINA
       ===================
    
    
    CATALINA_DEFINE  = [default]
    CATALINA_INCLUDE = [default]
    CATALINA_LIBRARY = [default]
    CATALINA_TARGET  = [default]
    CATALINA_LCCOPT  = [default]
    CATALINA_TEMPDIR = [default]
    LCCDIR           = [default]
    Catalina Compiler 3.0
    cpp: NEW.C:8 Could not find include file "plugin_array.h"
    cpp: NEW.C:39 No newline at end of file
    Press any key to continue . . .
    
    But of course we are going backwards a little here, because in getting to where I have already got, I had to pull apart the three #includes to find code that was critical to getting the one bit of code working - which is the write of a zero to 7fd4.

    A write to 7fcc does not work on my board. But of course I have hardcoded some things to try to get as much as possible out of any #includes so it is clearer what is going on. EG DUM is 8, and ANY_COG is 7

    Can we eliminate any variables by thinking about code with no #includes?

    Hi Dr_A,

    I'll generate you a version you can compile and run from your IDE.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-04 05:17
    Thanks Ross, and thanks for your patience.

    Now that I can test pasm code quickly I tried about 20 combinations and while nothing works, I have learned quite a bit. I did a debug routine and you are correct
    No - it writes it to address 0x7ff0, since this is what t1 contains.

    (Even debugging is hard, since catalina has paused at this point so has to be unpaused by forcing a write to 7fd4).

    My C code is this
    	return_value = _sys_plugin (plugin_type, 1);
    

    and deconstructing the pasm code and hardwired some values
    rosscode
    '              cogid     t1                      ' get ...
    	  mov		t1,#7					  ' hard code 7
                  shl       t1,#2                   ' ... our ...
    
    '              add       t1,par                  ' ... registry block
    		add		t1,sevenfdfour      ' hard code the registry address
                  rdlong    rqstptr,t1              ' register ...
                  and       rqstptr,low_24          ' ... this ...
                  wrlong    zero,rqstptr            ' ... plugin ...
                  mov       t2,#8                 ' ... as ...
                  shl       t2,#24                  ' ... the ...
                  or        t2,rqstptr              ' ... dummy ...
                  wrlong    t2,t1                   ' ... type
    
    service_loop
                  rdlong    t1,rqstptr wz           ' service request?
            if_z  jmp       #service_loop           ' no - just keep waiting
    
                  mov       time,cnt                ' yes - wait ...
                  add       time,five_seconds        ' ... for ...
                  waitcnt   time,#0                 ' ... five seconds
    
                  wrlong    zero,rqstptr            ' release the kernel
    
                  jmp       #service_loop           ' wait for another request
    

    But if we simplify this down, at the end of the day, is it not just the "wrlongs" that matter?

    In which case, we have three of these

    1)
    wrlong zero,rqstptr ' this writes a zero to hub ram 0x7fcc

    2)
    wrlong t2,t1 ' this writes 0x08007fcc to hub ram 0x7fcc

    3) release the kernel

    wrlong zero,rqstptr ' this writes zero to 0x7fcc


    If that is correct, then maybe it is my supporting C code that is incorrect - in particular the way I am loading cog code into cog code, unregistering it, then reregistering cog 7 as a dummy.
  • RossHRossH Posts: 5,519
    edited 2011-05-04 05:54
    Dr_Acula wrote: »
    Thanks Ross, and thanks for your patience.
    Well, it's my turn to eat humble pie!

    I just found a bug in the kernel that only affected XMM programs, and only those that used a plugin type of 8 - which just happens to be the number I chose to use for the DUM plugin!

    This would explain why it works on my DRACBLADE (since I compile it in LMM mode) and not on yours (since your IDE always compiles programs in XMM mode).

    Attached you will find two files:
    • Catalina_XMM.spin is an updated XMM kernel that needs to be copied to your target directory, overwriting the existing version.
    • test_plugin_2.c is a single-file version of the test_plugin program that does not need to include any other files (i.e. I have just applied homespun and spinc to the the PASM plugin, and then manually included the result in the appropriate place in the C source).
    I compiled and loaded test_plugin_2 using the commands ...
    catalina test_plugin_2.c -lc -D DRACBLADE -D LARGE
    payload XMM test_plugin_2
    
    ... but you should be able to compile it using your IDE.
    Hopefully, this will get the test program working for you, and then we can move on from there.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-04 06:10
    I'll test this in a moment. I'm just going to note something I have realised with my code as well which could be relevant.

    When I load up my cog, I think I need a delay to run the subsequent C instructions that unregister and reregister the plugin. If the delay is 1 second, my hack of writing to 7fd4 does not work, so I couldn't debug it any further.

    But I think a delay is needed before writing zero/value/zero.
    draccode	 ' wait , then write a zero, write 08007fcc to 7ff0 then write a zero again
    
    '		   wrlong zero,sevenfdfour ' this always works if here
    
                   mov	t2,delay		' 1 sec delay if delay = 80000000?
    	        add t2,cnt
    		  waitcnt	t2,delay
    
    '		   wrlong zero,sevenfdfour ' this works if delay is short??
    
    		  mov rqstptr,sevenffzero		' location of registry for cog 7
    		  wrlong	zero,rqstptr		' write a zero to 0x7ff0
    	        wrlong    newregistry,rqstptr      ' write 08007fcc to 0x7ff0
    		  wrlong	zero,rqstptr		' write a zero to 0x7ff0
    
    
    dracloop      jmp 	#draccode
    

    Now off to test your code...
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-04 06:15
    Ok, Woot, your program works!

    Do you have the source for the code in the plugin array?
  • RossHRossH Posts: 5,519
    edited 2011-05-04 06:24
    Dr_Acula wrote: »
    Ok, Woot, your program works!

    Do you have the source for the code in the plugin array?

    The source is plugin.spin from the plugin.zip file. I just compiled it with homespun, and then ran spinc on it.

    I'm afraid I'm off to bed now - but thank goodness we're finally making progress!

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-04 06:28
    We are indeed making progress - this is great.

    This is the relevant bit of the C code - load in a cog, unregister it, reregister a fake cog, wait for a reply 2 secs later
    	printf("Test program to pause catalina\n");
        	reg = _registry(); 							// address of registry
    	printf("Registry is at %x \n",reg);
    	print_registry();
    	readcog("plugin.cog",cogject_plugin);
    	plugin_parameters[1] = (unsigned long) reg;			// array[0] is always a pointer to the array itself, so start at 1
    	plugin_engine_start(7,cogject_plugin,plugin_parameters);
    	printf("Cog plugin loaded \n",reg);
    	print_registry();							// print again, should have changed
           _unregister_plugin(7);						// unregister cog 7 but don't stop it running
    	printf("Unregister cog 7\n");
    	_register_plugin(7, 8);						// register a fake cog number eg 7 is free, and with 8=DUM
    	printf("Reregister cog 7 as a dummy plugin\n");
           cog = _locate_plugin(8);
    	printf("Cog number = %x \n",cog);					// should print 7
    	return_value = _sys_plugin (plugin_type, 1); 			// program should hang here - see demo plugin.spin
    	printf("Return value = %i \n",return_value);			// and not print this unless pluging registered and returning a zero
    	printf("End program\n");
           while (1);                                                    // Prop reboots on exit from main()
    

    and this is the pasm bit
    draccode	 
    
    		  mov rqstptr,sevenfcc			' rqstptr = 7fcc
    		  wrlong	zero,rqstptr		' write a zero to 0x7fcc
    	        wrlong    newregistry,sevenffzero      ' write 08007fcc to 0x7ff0
    
                  mov       time,cnt                ' yes - wait ...
                  add       time,two_seconds        ' ... for ...
                  waitcnt   time,#0                 ' ... two seconds
    
    		  wrlong	zero,rqstptr		' write a zero to 0x7fcc, restarts catalina
    
    
    dracloop      jmp 	#dracloop ' endless loop
    

    However, the reason the C code is doing this in a roundabout way is to debug the error which you found last night (the code needed to keep C running as long as possible to print debug values on the screen.) So now this is working, it should be possible to write much simpler C code. Back to coding!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-04 17:51
    Now we are having fun. This is a demo program that reads a plugin off the sd card, keeps it in external ram, then loads it into a cog as needed, all from C
    #include <stdio.h>
    
    // compile with catalina -lcx -D PLUGIN -lm -x5 -M 256k -d DRACBLADE -D HIRES_VGA myprog.c
    // compile using XMM
    
    // cogjects - sd card driver in catalina is a little slow so load up once into external ram then (re) load quicker from external ram
    	unsigned long cogject_plugin[512];					// external memory for plugin
    
    // *************** functions ***************************************
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    int external_plugin_cog_load(int cognumber, unsigned long cogdata[])    	//  load a plugin from external memory
    {
    	unsigned long hubcog[512];						// create a local array, this is in hub ram, not external ram
    	int i;
    	int result;
    	for(i=0;i<512;i++)
    	{
    		hubcog[i]=cogdata[i];					// move from external memory to a local array in hub
    	}
     	_coginit (_registry() >> 2, (int) hubcog >> 2, cognumber); 	// pass the registry, location of cog data and cog to load into
    	return result;
    }
    
    int EoF (FILE* stream)
    {
      	register int c, status = ((c = fgetc(stream)) == EOF);
      	ungetc(c,stream);
      	return status;
    }
    
    void readcog(char *filename,unsigned long external_cog[])		// read in a .cog file into external memory array
    {
    	int i;
    	FILE *FP1;
    	i = 0;
    	if((FP1=fopen(filename,"rb"))==0)					// open the file
       	{
      		fprintf(stderr,"Can't open file %s\n",filename);
    		exit(1);
       	}
      	fseek(FP1,0,0);
    	for(i=0;i<24;i++)
    	{
    		getc(FP1);							// read in the first 24 bytes and discard
    	}
    	i = 0;
      	while(!EoF(FP1) & (i<505))						// run until end of file or 511-6
    	{
    		external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24);	// get the long
    		i+=1;
    	}
    	if(FP1)
           {
         		fclose(FP1);							// close the file
         		FP1=NULL;
       	}
    	//printf("external array cog first long = 0x%x \n",external_cog[0]);	// hex value
    }
    
    void main ()
    {
    	int result;
    	printf("Test program to pause catalina\n");
    	readcog("plugin.cog",cogject_plugin);				// read from sd card into an external memory array
    	result = external_plugin_cog_load(7, cogject_plugin);		// move plugin from external memory to cog
           printf ("\nthis should take 5 seconds...\n");			// plugin programmed to delay for 5 secs
           result = _sys_plugin(8, 1); 					// 8 is dummy plugin, and 1 is any non zero number
           printf("Result (should be zero) = %i \n",result);
           while (1);                                                    // Prop reboots on exit from main()
    }
    
    /*
    ''
    '' Simple plugin that waits 5 seconds, then returns.
    ''
    
    CON
    
      _clkfreq = 80_000_000                                              ' 5Mhz Crystal
      _clkmode = xtal1 + pll16x                                          ' x 16
    
    PUB Main
        coginit(1,@entry,0)                                           ' cog 1, cogstart, dummy value
    
    DAT
                  org       0
    entry
                  cogid     t1                      ' get ...          t1=7
                  shl       t1,#2                   ' ... our ...      t1=28
                  add       t1,par                  ' ... registry block     par=7fd4, t1=7ff0
                  rdlong    rqstptr,t1              ' register ...         rqstptr = 08007fcc
                  and       rqstptr,low_24          ' ... this ...         rqstptr = 00007fcc
                  wrlong    zero,rqstptr            ' ... plugin ...       hub ram 7fcc = 0
                  mov       t2,#8                 ' ... as ...           t2=8 = dummy value
                  shl       t2,#24                  ' ... the ...          t2=08000000
                  or        t2,rqstptr              ' ... dummy ...        t2=08007fcc
                  wrlong    t2,t1                   ' ... type             hub ram 7ff0 = 08007fcc
    
    service_loop
                  rdlong    t1,rqstptr wz           ' service request?     check 7fcc
            if_z  jmp       #service_loop           ' no - just keep waiting
    
                  mov       time,cnt                ' yes - wait ...
                  add       time,five_seconds        ' ... for ...
                  waitcnt   time,#0                 ' ... five seconds
    
                  wrlong    zero,rqstptr            ' release the kernel       write zero to 7fcc
    
                  jmp       #service_loop           ' wait for another request
    
    low_24        long       $00FFFFFF
    five_seconds  long       _clkfreq*5
    
    time          long       0
    rqstptr       long       0
    t1            long       0
    t2            long       0
    zero          long       0
    */
    
    
    

    Ok, let's say I want to pass an array to the cog. I can get the address of the array in C using a pointer. I can read the registry in C, work out I'm using cog 7, multiply by 4, add to the registry value, read the long in that location, and work out that 7fcc is the communication long. Is there a long above or below this that is used as a way of passing data back and forward?
  • RossHRossH Posts: 5,519
    edited 2011-05-04 18:07
    Dr_Acula wrote: »
    Ok, let's say I want to pass an array to the cog. I can get the address of the array in C using a pointer. I can read the registry in C, work out I'm using cog 7, multiply by 4, add to the registry value, read the long in that location, and work out that 7fcc is the communication long. Is there a long above or below this that is used as a way of passing data back and forward?

    No - just use the long you have identified. The convention Catalina uses is that the "communication long" (as you call it - I tend to call it the "request long") contains a code in the top 8 bits, and then either:
    • 24 bits of data in the lower 24 bits, or
    • 24 bits of address that point to another block of data (which you must allocate and manage!)
    The first case is called a short request, and the second is called a long request. There are suitable functions (and structures) defined in catalina_plugin.h to make these easy to use.

    All you need to do is decide on one or more codes you want to use (which must be non-zero) - then both the plugin and the C program must know the codes, and must also know whether each code represents a short or long request. For examples, see any of the HMI plugins.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-04 18:45
    Thanks Ross. I think that is the last piece of the jigsaw.

    Is the request long this line of code? (or is it 7ff0)
                  rdlong    t1,rqstptr wz           ' service request?     check 7fcc
            if_z  jmp       #service_loop           ' no - just keep waiting
    

    If so, is the check on "z" looking for the entire long being zero, or just some of the bits?

    I sent the US$250 through your sourceforge link to say thanks for all the coding, particularly for getting it working last night. This sort of instant support is what makes Catalina such a pleasure to use!
  • RossHRossH Posts: 5,519
    edited 2011-05-04 19:21
    Dr_Acula wrote: »
    Thanks Ross. I think that is the last piece of the jigsaw.

    Is the request long this line of code? (or is it 7ff0)
                  rdlong    t1,rqstptr wz           ' service request?     check 7fcc
            if_z  jmp       #service_loop           ' no - just keep waiting
    
    If so, is the check on "z" looking for the entire long being zero, or just some of the bits?

    I sent the US$250 through your sourceforge link to say thanks for all the coding, particularly for getting it working last night. This sort of instant support is what makes Catalina such a pleasure to use!

    Dr_A,

    You didn't need to do that, but thanks very much!

    As to your question, yes, the request long is the one the plugin is polling for a non-zero value (i.e. $7fcc). Any non-zero value in any of the bits triggers the exit from that loop, and in the case of this plugin that's all that's required - but most plugins would decode the value to see what service is being requested. As I said earlier, by convention this is the value in the upper 8 bits, and this value tells the plugin how to interpret the lower 24 bits - i.e. as an address or as data.

    By the way - have you noticed the demo program called test_plugin_names.c in the demo folder? This program will print out the registry address, plus the registered type and the request block address for each loaded plugin. You can take the code out of that program for inclusion in your own program for debugging purposes.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-05 18:45
    Thanks for the pointer to test_plugin_names. I am working on the plugin and C code now at the same time so this will come in handy.

    Just a thought about something Cluso and I discussed last week - as the size of a C program grows, the download time starts to get significant. It isn't a problem now with a 160k program, but anything that might run on Jazzed's megabyte boards would take a long time to download.

    I wonder if it is possible to do a download directly via USB?

    The propeller would be a USB slave, so that is a lot easier coding than being a host. One could think about downloading via serial a small startup program that then uses the same or different pins to get a USB connection going. Cluso felt that this could give a 10 fold increase in speed.

    Would this be practical?

    Also, would the speed start to be limited by the sd card write speed (and would a solution to that be Kye's sd driver)?
  • RossHRossH Posts: 5,519
    edited 2011-05-05 19:25
    Dr_Acula wrote: »
    Thanks for the pointer to test_plugin_names. I am working on the plugin and C code now at the same time so this will come in handy.

    Just a thought about something Cluso and I discussed last week - as the size of a C program grows, the download time starts to get significant. It isn't a problem now with a 160k program, but anything that might run on Jazzed's megabyte boards would take a long time to download.

    I wonder if it is possible to do a download directly via USB?

    The propeller would be a USB slave, so that is a lot easier coding than being a host. One could think about downloading via serial a small startup program that then uses the same or different pins to get a USB connection going. Cluso felt that this could give a 10 fold increase in speed.

    Would this be practical?

    Also, would the speed start to be limited by the sd card write speed (and would a solution to that be Kye's sd driver)?
    Yes, serial is slow - even with USB speeds, loading a 16Mb program this way would be annoyingly slow. I generally only use serial for one-off loads (typically only during the initial debugging steps).

    These days nearly all prop boards seem to have an SD card (or one can be added) so I have Catalyst loaded into EEPROM - then If I want to load a large program I just put the SD Card in my PC, copy the binary to it, and reinsert it into the Prop. Easy!

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-05 19:43
    Yes I do that too. It works up to a point but the unplugging gets a little tedious.

    I was thinking a USB connection would be easier.

    But what you have said there raises another intriguing possibility. I have my little $2 USB to SD card adaptor. What if one could hack into that, and switch the 4 lines from the SD card to either the propeller or to a USB? There are only a handful of components on these adaptors - maybe the chips themselves are easily available (they can't be expensive since these adaptors are on ebay for $2 and that includes the plug and the case as well).

    That could be a "no software" solution. Or at least a minimal software - maybe the propeller could devote an output pin to switch how the USB is controlled.

    Or maybe an autodetect? My android pandapad works like that - normally its internal sd card is a drive within the android, but if you plug in a USB cable it switches to become a slave drive on the PC.

    One advantage of this hardware solution is you can go straight to USB2 speeds without having to code any software. Then a 32Mb program would be very fast.
  • RossHRossH Posts: 5,519
    edited 2011-05-05 21:22
    Dr_Acula wrote: »
    Yes I do that too. It works up to a point but the unplugging gets a little tedious.

    I was thinking a USB connection would be easier.

    But what you have said there raises another intriguing possibility. I have my little $2 USB to SD card adaptor. What if one could hack into that, and switch the 4 lines from the SD card to either the propeller or to a USB? There are only a handful of components on these adaptors - maybe the chips themselves are easily available (they can't be expensive since these adaptors are on ebay for $2 and that includes the plug and the case as well).

    That could be a "no software" solution. Or at least a minimal software - maybe the propeller could devote an output pin to switch how the USB is controlled.

    Or maybe an autodetect? My android pandapad works like that - normally its internal sd card is a drive within the android, but if you plug in a USB cable it switches to become a slave drive on the PC.

    One advantage of this hardware solution is you can go straight to USB2 speeds without having to code any software. Then a 32Mb program would be very fast.
    The problem is that these ideas will only work on certain hardware (or they require additional hardware).

    The advantage of serial is that it works on every Prop platform. SD card is probably the next most common method for transferring files (every platform I own has one, although one of them I had to add myself). But once you go beyond that, your percentage of platforms supported are likely to be down in the single digits.

    I hope one day soon to get some time to speed up the payload program. That should help a bit. David Betz was also working on a faster loader. He may already have something working.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-07 01:41
    Good points. Probably leave it for the moment then. Am guessing that at about 300k to 400k a program will start getting too tedious to use serial.

    Below is a little demo program that sets up an array, starts a cog and the cog changes an element of that array. Very simple I know, but it is the building block for porting cogjects into plugins, pausing catalina and then using the XMM memory pins for other purposes.
    #include <stdio.h>
    
    // compile with catalina -lcx -D PLUGIN -lm -x5 -M 256k -d DRACBLADE -D HIRES_VGA myprog.c
    // compile using XMM
    
    // cogjects - sd card driver in catalina is a little slow so load up once into external ram then (re) load quicker from external ram
    	unsigned long cogject_plugin[512];					// external memory for plugin
    
    // *************** functions ***************************************
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void pokelong(int address, unsigned long value)				// poke a long into hub memory 'little endian'
    {
    	poke(address+0, (char) (value & 0x000000ff));
    	poke(address+1, (char) ((value & 0x0000ff00) >> 8));
    	poke(address+2, (char) ((value & 0x00ff0000) >> 16));
    	poke(address+3, (char) ((value & 0xff000000) >> 24));
    }
    
    unsigned long peeklong(int address)				// peek a long from hub memory 'little endian'
    {
    	unsigned long value;
    	value = peek(address) | (peek(address+1) <<8) | (peek(address+2) <<16) | (peek(address+3)<<24);
    	return value;
    }
    
    int external_plugin_cog_load(int cognumber, unsigned long cogdata[])    	//  load a plugin from external memory
    {
    	unsigned long hubcog[512];						// create a local array, this is in hub ram, not external ram
    	int i;
    	int result;
    	for(i=0;i<512;i++)
    	{
    		hubcog[i]=cogdata[i];					// move from external memory to a local array in hub
    	}
     	_coginit (_registry() >> 2, (int) hubcog >> 2, cognumber); 	// pass the registry, location of cog data and cog to load into
    	return result;
    }
    
    int EoF (FILE* stream)
    {
      	register int c, status = ((c = fgetc(stream)) == EOF);
      	ungetc(c,stream);
      	return status;
    }
    
    void readcog(char *filename,unsigned long external_cog[])		// read in a .cog file into external memory array
    {
    	int i;
    	FILE *FP1;
    	i = 0;
    	if((FP1=fopen(filename,"rb"))==0)					// open the file
       	{
      		fprintf(stderr,"Can't open file %s\n",filename);
    		exit(1);
       	}
      	fseek(FP1,0,0);
    	for(i=0;i<24;i++)
    	{
    		getc(FP1);							// read in the first 24 bytes and discard
    	}
    	i = 0;
      	while(!EoF(FP1) & (i<511))						// run until end of file or 511-6
    	{
    		external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24);	// get the long
    		i+=1;
    	}
    	if(FP1)
           {
         		fclose(FP1);							// close the file
         		FP1=NULL;
       	}
    	//printf("external array cog first long = 0x%x \n",external_cog[0]);	// hex value
    }
    
    void print7fcc()
    {
    	int i;
    	char peekbyte;
    	printf("4 bytes from 7fcc to 7fc3 are ");
    	for (i=0;i<4;i++)
    	{
    		peekbyte = peek(0x7fcc+i);
    		if (peekbyte < 16)
    		{
    			printf("0");
    		}
    		printf("%x ",peekbyte);
    	}
    	printf ("\n");	// carriage return
    }
    
    void print_registry()		// 32 bytes
    {
    	int reg;
    	int i;
    	char peekbyte;
    	reg = _registry();
    	printf("0x%x = ",reg);
    	for (i=0;i<32;i++)
    	{
    		peekbyte = peek(reg+i);
    		if (peekbyte < 16)
    		{
    			printf("0");
    		}
    		printf("%x",peekbyte);
    
    	}
    	printf ("\n");	// carriage return
    }
    
    void pass_plugin_data(unsigned long p_array[],int cognumber)
    {
    	int reg;
    	int a;								
    	unsigned long b,c;
    	print_registry();
    	reg = _registry();
    	a=reg + (cognumber << 2); 						// registry + cognumber *4
    	b=peeklong(a);							// get the registry for this cog ff007fcc
    	b = b & 0x0000ffff;							// mask off upper two bytes
    	c = (unsigned long) &p_array[0];					// pointer to p_array
    	printf("pointer value is %x \n",c);
    	pokelong(b,c);							// address,value 7fcc now contains a pointer to the p_array[0]
    	print7fcc();			
    }
    
    void main ()
    {
    	int result;
    	unsigned long p_array[3] = {1,2,3};
    	printf("Test program to pause catalina\n");
    	pass_plugin_data(p_array,7);					// pass some data
    	readcog("plugin.cog",cogject_plugin);				// read from sd card into an external memory array
    	result = external_plugin_cog_load(7, cogject_plugin);		// move plugin from external memory to cog
           printf ("\nthis should take 2 seconds...\n");			// plugin programmed to delay for 5 secs
           result = _sys_plugin(8, 1); 					// 8 is dummy plugin, and 1 is any non zero number
           printf("Result (should be zero) = %i \n",result);
    	printf("value of p_array[0] = %x \n",p_array[0]);
    	printf("value of p_array[1] = %x \n",p_array[1]);
    	printf("value of p_array[2] = %x \n",p_array[2]);
    //	printf("debug value @ 0x1000 = 0x%x \n",peeklong(0x1000));		// useful debug location
           while (1);                                                    // Prop reboots on exit from main()
    }
    
    

    and the pasm part
    ''
    '' Simple plugin that waits 5 seconds, then returns.
    ''
    
    CON
    
      _clkfreq = 80_000_000                                              ' 5Mhz Crystal
      _clkmode = xtal1 + pll16x                                          ' x 16
    
    PUB Main
        coginit(1,@entry,0)                                           ' cog 1, cogstart, dummy value
    
    DAT
                  org       0
    entry
                  cogid     t1                      ' get ...          t1=7
                  shl       t1,#2                   ' ... our ...      t1=28
                  add       t1,par                  ' ... registry block     par=7fd4, t1=7ff0
                  rdlong    rqstptr,t1              ' register ...         rqstptr = 08007fcc
                  and       rqstptr,low_24          ' ... this ...         rqstptr = 00007fcc
    		rdlong	   arraypointer,rqstptr     ' save for later as 7fcc gets changed below arraypointer = 6ab4
                  wrlong    zero,rqstptr            ' ... plugin ...       hub ram 7fcc = 0
                  mov       t2,#8                 ' ... as ...           t2=8 = dummy value
                  shl       t2,#24                  ' ... the ...          t2=08000000
                  or        t2,rqstptr              ' ... dummy ...        t2=08007fcc
                  wrlong    t2,t1                   ' ... type             hub ram 7ff0 = 08007fcc
    
    service_loop
                  rdlong    t1,rqstptr wz           ' service request?     check 7fcc
            if_z  jmp       #service_loop           ' no - just keep waiting
    
                  mov       time,cnt                ' yes - wait ...
                  add       time,two_seconds        ' ... for ...
                  waitcnt   time,#0                 ' ... two seconds
    
    ' change the first element of the array
    		rdlong	    t1,arraypointer		' get array[0] (6ab4) in t1 
    		add	    t1,#10			' add 10
    		wrlong	    t1,arraypointer		' write back to hub value, address
    
                  wrlong    zero,rqstptr            ' release the kernel       write zero to 7fcc
    
    finish        jmp       #finish 			' finish
    
    low_24        long       $00FFFFFF
    two_seconds  long       _clkfreq*2
    
    time          long       0
    rqstptr       long       0
    t1            long       0
    t2            long       0
    zero          long       0
    'sixabfour	long	    $6AB4
    'sevenfcc	long	    $7FCC
    arraypointer  long	    0 
    'debug		long	    $1000	' for debugging
    'testvalue	long	    $12345678
    
  • RossHRossH Posts: 5,519
    edited 2011-05-07 17:50
    UPDATE: Another small patch release (3.0.2) is now available, and is attached to this post. This patch release must be installed over an existing Catalina 3.0 installation. This is a cumulative patch that contains all the bug fixes from previous patches. Here are the main changes:
    • Fixed a bug in the plugin search algorithm used in the XMM kernel which meant the search stopped when the plugin type was 8 instead of when it reached cog number 8! This meant that plugin type 8 (allocated to the DUM plugin) could never be found in XMM programs.
    • Fixed some typos in the definition of the waitpne and waitpeq macros in the header file catalina_icc.h
    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-08 06:10
    Hi Ross,

    I've got a lot of things working in a plugin, but I've come across a small problem with one of the pins - P8 on the chip stays high.

    I've narrowed it down to this little bit of code to replicate the problem
                  org       0
    entry
                  cogid     t1                      ' get ...          t1=7
                  shl       t1,#2                   ' ... our ...      t1=28
                  add       t1,par                  ' ... registry block     par=7fd4, t1=7ff0
                  rdlong    rqstptr,t1              ' register ...         rqstptr = 08007fcc
                  and       rqstptr,low_24          ' ... this ...         rqstptr = 00007fcc
                    rdlong     arraypointer,rqstptr     ' save for later as 7fcc gets changed below arraypointer = 6ab4
                  wrlong    zero,rqstptr            ' ... plugin ...       hub ram 7fcc = 0
                  mov       t2,#8                 ' ... as ...           t2=8 = dummy value
                  shl       t2,#24                  ' ... the ...          t2=08000000
                  or        t2,rqstptr              ' ... dummy ...        t2=08007fcc
                  wrlong    t2,t1                   ' ... type             hub ram 7ff0 = 08007fcc
    
    service_loop
                  rdlong    t1,rqstptr wz           ' service request?     check 7fcc
            if_z  jmp       #service_loop           ' no - just keep waiting
    
    
    ' ********* debug routine to test why pin 8 stays high
                  mov     dira, latch_dir                         ' set latch direction, enable pins 0-11
    		mov t1,zero
    		mov outa,t1					' should leave all pins 0-11 low but instead pin 8 is high
    		jmp #finish
    
    finish        jmp       #finish                         ' finish
    
    ' *************** variables ******************************************************************
    
    low_24        long       $00FFFFFF
    two_seconds   long       _clkfreq*2
    twohundredms	long       _clkfreq/5
    
    time          long       0
    rqstptr       long       0
    i             long       0
    t1            long       0
    t2            long       0
    zero          long       0
    data          long       0
    minusone      long       $FFFFFFFF
    'sixabfour      long        $6AB4
    'sevenfcc       long        $7FCC
    arraypointer  long          0 
    debug          long        $1000       ' for debugging
    testvalue      long        $12345678
    lowmask	long	   %00000000_00000000_00000000_11111111
    ' *** LCD variables ***
    
    latch_dir       long    %00000000_00000000_00001111_11111111    ' 138 active, gate active and 8 data lines active
    latch_lcd       long    %00000000_00000000_00001010_00000000    ' LCD latch is xxxx101x and gate low xxxxxxx0
    enable_lcd      long    %00000000_00000000_00000000_00000010    ' Enable pin 6 on LCD displays
    lcd_delay       long    300_000
    
    

    The
    mov     dira, latch_dir                         ' set latch direction, enable pins 0-11
    

    ought to enable the lower 12 pins of the propeller

    and
    		mov t1,zero
    		mov outa,t1					' should leave all pins 0-11 low but instead pin 8 is high
    

    ought to leave the pins low.

    On my board, pin 8 has a 10k pullup so there are two possibilities
    1) the mov dira is being overwritten by something that puts pin 8 back to being tristate (not the other pins though - these stay low)
    2) Somthing in catalina is changing the pin high.

    I thought maybe catalina hadn't quite shutdown by the time the service request has come though but adding a delay after this but before taking over the pins doesn't seem to help.

    Can you think of any reason this pin is staying high?
  • kuronekokuroneko Posts: 3,623
    edited 2011-05-08 06:17
    Simple test, shut down every other cog. If the pin goes down (as intended) then someone else is driving it. Or start with validating dira/outa by toggling a specific pin/light an LED if it holds the correct value.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-08 06:40
    Thanks kuroneko. I have added code to catalina to shut down cog 0,1,3,4,5,6.

    Cog 7 is running my code.

    This only leaves one cog running - cog 2 which is the cog that is running catalina. I also put the code to put the pin low into a loop but it still is high. All most strange...
    loop          mov     dira, latch_dir                         ' set latch direction, enable pins 0-11
    		mov t1,zero
    		mov outa,t1					' should leave all pins 0-11 low but instead pin 8 is high
    		jmp #loop
    
  • kuronekokuroneko Posts: 3,623
    edited 2011-05-08 06:54
    What I meant was to do this from your PASM test code (running in cog 7). For this test even shut down cog 2.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-08 07:22
    Thanks kuroneko - that has been most useful.

    After testing lots of combinations shutting down cogs from pasm, it seems cog 1 is the problem, not cog 2. I'll need to find out what cog 1 is running.
  • RossHRossH Posts: 5,519
    edited 2011-05-08 16:20
    Dr_Acula wrote: »
    Thanks kuroneko - that has been most useful.

    After testing lots of combinations shutting down cogs from pasm, it seems cog 1 is the problem, not cog 2. I'll need to find out what cog 1 is running.
    Hi Dr_A,

    The code in the test_plugin_names.c shows how to easily print out from C what's running in each cog. Just add this to your existing program. Let me know what it is and I'll investigate.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-09 07:00
    Huge amounts of progress. I put in a cogstop for cog 1 and then dropped in the entire 20x4 LCD display code and it works brilliantly. The Catalina IDE has been very useful here as it is possible to compile and download pasm code and C code independently from the same program and hence quickly debug ideas. What this means is that not only is a plugin possible but also that it is possible to share pins with catalina. This is going to be very useful for the "Propeller GUI" project.

    Ran test_plugin_names and cog1 is half the screen driver. (0=keyboard, 1=screen, 2=kernel, 3=screen, 4=hmi, 5=float_a, 6=sd file, 7=unused"

    So something in that screen driver seems to be holding pin 8 high.
  • RossHRossH Posts: 5,519
    edited 2011-05-09 15:59
    Dr_Acula wrote: »
    Huge amounts of progress. I put in a cogstop for cog 1 and then dropped in the entire 20x4 LCD display code and it works brilliantly. The Catalina IDE has been very useful here as it is possible to compile and download pasm code and C code independently from the same program and hence quickly debug ideas. What this means is that not only is a plugin possible but also that it is possible to share pins with catalina. This is going to be very useful for the "Propeller GUI" project.

    Ran test_plugin_names and cog1 is half the screen driver. (0=keyboard, 1=screen, 2=kernel, 3=screen, 4=hmi, 5=float_a, 6=sd file, 7=unused"

    So something in that screen driver seems to be holding pin 8 high.

    Hi Dr_A,

    I presume you are using the HiRes VGA driver? That's a parallax driver, pretty much unmodified - I'll have a look at it tonight.

    EDIT: Please confirm that you ran the code from the test_plugin_names in the program that actually exhibits the problem - just running that program separately is likley to give a different set of cogs, and we could end up looking at the wrong driver!

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-09 17:17
    EDIT: Please confirm that you ran the code from the test_plugin_names in the program that actually exhibits the problem - just running that program separately is likley to give a different set of cogs, and we could end up looking at the wrong driver!

    No I ran it as a separate program. Also I needed to add back in the math routines which takes a cog, otherwise it would not compile and gave two errors about "pow" and "log10". So how would I go about combining test_plugin_names into my program and avoid that math routine error? (which I think is buried in an include somewhere).
  • RossHRossH Posts: 5,519
    edited 2011-05-09 17:35
    Dr_Acula wrote: »
    No I ran it as a separate program. Also I needed to add back in the math routines which takes a cog, otherwise it would not compile and gave two errors about "pow" and "log10". So how would I go about combining test_plugin_names into my program and avoid that math routine error? (which I think is buried in an include somewhere).

    Hi Dr_A,

    You could compile with the integer only library (-lci) instead of the standard library(-lc), but I've also rewritten the code to not use printf() (which was pulling in the maths functions):
    #include <catalina_plugin.h>
    #include <catalina_hmi.h>
    
    char *name(int type) {
       switch (type) {
          case 0  : return "Kernel";
          case 1  : return "HMI";
          case 2  : return "Library";
          case 3  : return "Float_A";
          case 4  : return "Float_B";
          case 5  : return "Real-Time Clock";
          case 6  : return "SD File System";
          case 7  : return "Serial I/O";
          case 8  : return "Dummy";
          case 9  : return "Graphics";
          case 10 : return "Keyboard";
          case 11 : return "Screen";
          case 12 : return "Mouse";
          case 13 : return "Proxy";
          default : return "Unknown/None";    
       }
    }
    
    void print_plugin_names() {
       int i;
       int type;
       request_t *rqst;
    
       for (i = 0; i < 8; i++) {
          type = REGISTERED_TYPE(i);
          rqst = REQUEST_BLOCK(i);
          
          //t_printf("Cog %d (%x) Type = %s\n", i, (unsigned)rqst, name(type)); 
          t_string(1, "Cog ");
          t_integer(1, i);
          t_string(1, " (");
          t_hex(1, (unsigned)rqst);
          t_string(1, ") Type = ");
          t_string(1, name(type));
          t_char(1, '\n'); 
       }
    }
    
    Just include the above code in your program, then call print_plugin_names() from somewhere in your main() function.

    Ross.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-11 03:05
    Hi Ross,

    I've done some experiments. Some of the results are a bit confusing.
    1) The printout from my program with your code pasted in
    0=keyboard
    1=screen
    2=kernel
    3=screen
    4=HMI
    5=float_a
    6=sd

    Next - add this code into the C program:
    // _cogstop(0); // not screen
    // _cogstop(1); // screen - needs 1 and 3 running
    // _cogstop(2); // not screen
    // _cogstop(3); // screen - needs 1 and 3 running
    // _cogstop(4); // not screen
    // _cogstop(5); // not screen
    // _cogstop(6); // not screen

    And the experiment seems to concur with the printout - ie if either cog 1 or cog 3 is stopped then the screen goes blank.

    However, there does not seem to be a combination that allows the LCD display to work.

    Next, experiments within the PASM code

    ' cogstop 0 ' ? screen
    ' cogstop 1 ' cog 1 is the one that needs to be stopped to get the LCD to work
    ' cogstop 2
    ' cogstop 3
    ' cogstop 4
    ' cogstop 5
    ' cogstop 6


    This is where things get strange. Stopping cog 1 allows the LCD display to work. Stopping cog 0 makes the screen go blank (0 is the keyboard in the C code). And stopping all of cogs 2 to 6 with cogs 0 and 1 enabled and the screen still is on.

    So I am not sure whether cogstop in pasm is the same as cogstop in C.

    And so as a result of this, I am not at all sure what is running in cog 1 (pasm) which is the one that needs to be disabled to get the LCD display to work.

    Help here would be most appreciated!
  • kuronekokuroneko Posts: 3,623
    edited 2011-05-11 06:21
    Dr_Acula wrote: »
    Next, experiments within the PASM code

    ' cogstop 0 ' ? screen
    ' cogstop 1 ' cog 1 is the one that needs to be stopped to get the LCD to work
    ' cogstop 2
    ' cogstop 3
    ' cogstop 4
    ' cogstop 5
    ' cogstop 6
    Is that how you wrote it (in PASM)? Just checking ... because cogstop takes its parameter in D rather than S so you'd have to do at least something like
    cogstop $+1
        long    1          ' stop cog #1
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-05-11 06:45
    Thanks Kurenoko!

    Ok, well testing that with the cogs one at a time, and this is the line that allows the LCD display to work:
        cogstop $+1
        long    2          ' "long 1" = stop cog #1, long 2 = stop cog #2
    

    and I think that is stopping cog2. If that is true, then that would explain why I couldn't replicate the problem from C, because cog2 is the kernel and this is the one cog you can't stop before calling the driver because C needs to be running right up until the driver is called.

    So this might now be a question for Ross if it is the kernel that is still controlling pin 8.
Sign In or Register to comment.