Dave,
Thanks I see that now. How do you keep track of instruction bits?
Tom
I'm not sure I understand the question but the S field of an instructionis bits 8:0 and the D field is bits 17:9. The MOVS instruction will store the low order 9 bits of the source into bits 8:0 of the destination and MOVD will store the low order 9 bits of the source into bits 17:9 of the destination. Adding $200 to an instruction increments the D field since $200 is a constant with only bit 9 set which is the low order bit of the D field. After modifying an instruction, you must execute at least one other instruction before you can execute the modified instruction.
I'm thinking that the easiest way to make this work more generally is to modify the pasm to store ClockDelay and ClockState.
At the beginning of the pasm it tests for nonzero command.
So right after the "if_z jmp #loop" I would add the following.
mov t7, t1 '' move 'command' to new variable t7mov t8, t1 '' make a copy
and t7, #$40000 wz '' C program defines command 4 <<16 for start up
If_nz jmp #startup
Put startup at end of current code (but before 'done').
startup mov t7, t8 '' make t7 wholeand t7 , #1" first bit of command is Clockstate
mov ClockState, t7
mov t7, t8
shr t7, #2 " C packed ClockDelay in command by shifting ClockDelay << 2and t7, #$FFmov ClockDelay, t7
wrlong zero, par''set command back to zerojmp #loop
define after arg4 the following
t7 long0
t8 long0
In the C program, in the start function, after starting the cog, but before the return I would add the following
Dave,
I had already modified the spin file's pasm and once I fixed a couple of things, (like trying to use $40000 as an immediate), I tried it and it did work. I am thinking about trying to write a version, and would use your suggestion.
It is very fast getting 14+ blocks of Pixy data per frame, which is much faster than the spin or simpleIDE library versions.
My next step in this exercise is to put all of the spi constants (MSPRE, etc.) into the program. (The pixy only used MSPRE which = 2 in the original spin program), and the separate the parts into a library.
The revised C program and pasm are listed below, and the spin file is attached.
/* spipasm 3 - a fast spin interface library project
Updated to use pasm to set ClockDelay and ClockState
Use pasm modified from SPI_Asm.spin propeller tool library object.
T Montemarano (with a lot of help)
NOTES:
Uses spin file xSPIAsm.spin,
This version does run correctly.
The SPI device called in main() is a Pixy CMUCAM5. It does not required a start command
since it always transmits data at 1usec.
It should be possible to change main to use other spi devices
like the DS1620 used in the spi spin demo.
This version uses the same calls as the SPI_Asm.spin library object.
device->command is either 0 or packed with 2 or 3 numbers to be used by pasm.
command = 0 -- pasm in idle loop
in spipasm_start, the number 4 is shifted left 16 bits to indicate 'startup'
the ClockDelay value is shifted left 2 bits
the ClockState value is in bit 0. All 3 values are or'd.
in spipasm_SHIFTIN the number 2 is shifted left 16 bits, this is or'd with the address of the Dpin
in spipasm_SHIFTOUT, the number 1 is shifted left 16 bits, and or'd with the address of the Dpin
*/#include"simpletools.h"// Library includestypedefstructspipasm_struct // Structurecontainsvaraibles
{// for cogs to share + cog & stackvolatileint command;
int Dpin;
int Cpin;
volatileint Mode;
volatileint Bits;
volatileint Value;
volatileint Flag;
int cog; // Remembers cog for spiasm_stop
} spia_t; // Data type for structint pixydata[400];
int clkst = 0; // 0 = start clock low, 1 = start clock highint clkdly = 15; // ClockDelay, actual clock delay = 300ns + (clkdly-1) * 50ns// clkdly = 15 gives clock delay = 1 usec// function prototypesspia_t *spipasm_start(int clkdly, int clkst);
voidspipasm_stop(spia_t *device);
voidspipasm_SHIFTOUT(spia_t *device,
int DQ, int CLK, int MD, int BIT, int VLU);
intspipasm_SHIFTIN(spia_t *device,int DQ, int CLK, int MD, int BIT);
voidspipasm_setcommand(spia_t *device, int cmd, int *argptr);
/*
libblinkpasm.c
Test harness for the spipasm library.
*/// #include "spipasm.h"spia_t *spia;
intmain()// Main function{
int px;
// Put demo code here
spia = spipasm_start(clkdly, clkst); // Launch, get handlesint i = 1;
while(i<398) // fill pixydata array with spi bytes
{
// Pixy SPI interface continuously transmits data (no starting or stopping it)// Pixy data out rate is 1usec // Pixy SPI data out -> Prop P0, Pixy Clock -> Prop P2// spipasm_shiftin(Dpin, Cpin, Mode, Bits)
pixydata[i] = spipasm_SHIFTIN(spia, 0, 2, 0, 8); // Mode 0 = MSBPRE
i++;
}
i = 1;
while(i<398) // write pixydata array
{
// printi(" i = %d color = %x\n", i, pixydata[i]);
printi("%d\n", pixydata[i]);
i++;
}
spipasm_stop(spia);
}
// These are the actual functions // ****************************************spia_t *spipasm_start(int clkd, int clks){
spia_t *device; // Declare spipasm pointer
device = (void *) malloc(sizeof(spia_t)); // Allocate memory for it if(device->cog == 0)
{
device->command = 0; // pasm stays in waiting loop till non zeroexternint binary_xSPIAsm_dat_start[];
device->cog = 1 + cognew((void*)binary_xSPIAsm_dat_start, (void*)device);
}
device->command = (4 << 16) | (clkd << 2) | clks ; // pasm reads command, sets ClockDelay, ClockStatewhile(device->command); // wait till pasm resets command to zeroreturn device; // Return pointer to structure
}
// ************************************voidspipasm_stop(spia_t *device){
if(device->cog > 0) // If cog running
{
cogstop(device->cog - 1); // Shut down cog
device->cog = 0; // Clear cog varaiblefree(device); // Release allocated memory
}
}
// ************************************voidspipasm_SHIFTOUT(spia_t *device, int DQ, int CLK, int MD, int BIT, int VLU){
device->Dpin = DQ; // load variable values for pasm
device->Cpin = CLK;
device->Mode = MD;
device->Bits = BIT;
device->Value = VLU;
spipasm_setcommand(spia,1, &device->Dpin);
}
// ************************************intspipasm_SHIFTIN(spia_t *device,
int DQ, int CLK, int MD, int BIT){
device->Dpin = DQ;
device->Cpin = CLK;
device->Mode = MD;
device->Bits = BIT;
device->Flag = 1;
spipasm_setcommand(spia, 2, &device->Dpin);
while(device->Flag); // pasm sets Flag =0 when finished reading all bits in Valuereturn device->Value;
}
// ************************************voidspipasm_setcommand(spia_t *device, int cmd, int *argptr){
device->command = (int) argptr | (cmd << 16);
while(device->command);
}
DATorg' '' SPI Engine - main loop'
loop rdlong t1,parwz''wait for commandif_zjmp #loop
mov t7, t1 '' command to t7mov t8, t7 '' copy commandand t7, stconst wz'' test for startup if_nzjmp #startup
movd :arg,#arg0 ''get 5 arguments ; arg0 to arg4mov t2,t1 '' │mov t3,#5''───┘
:arg rdlong arg0,t2
add :arg,d0
add t2,#4djnz t3,#:arg
mov address,t1 ''preserve address location for passing''variables back to Spin language.wrlong zero,par''zero command to signify command receivedror t1,#16+2''lookup command addressadd t1,#jumps
movs :table,t1
rol t1,#2shl t1,#3
:table mov t2,0shr t2,t1
and t2,#$FFjmp t2 ''jump to command
jumps byte0''0byte SHIFTOUT_ ''1byte SHIFTIN_ ''2byte NotUsed_ ''3
NotUsed_ jmp #loop
'################################################################################################################'tested OK
SHIFTOUT_ ''SHIFTOUT Entrymov t4, arg3 wz'' Load number of data bitsif_zjmp #Done '' '0' number of Bits = Donemov t1, #1wz'' Configure DataPinshl t1, arg0
muxzouta, t1 '' PreSet DataPin LOWmuxnzdira, t1 '' Set DataPin to an OUTPUTmov t2, #1wz'' Configure ClockPinshl t2, arg1 '' Set Mask test ClockState, #1wc'' Determine Starting Stateif_ncmuxzouta, t2 '' PreSet ClockPin LOWif_cmuxnzouta, t2 '' PreSet ClockPin HIGH muxnzdira, t2 '' Set ClockPin to an OUTPUTsub _LSBFIRST, arg2 wz,nr'' Detect LSBFIRST mode for SHIFTOUTif_zjmp #LSBFIRST_
sub _MSBFIRST, arg2 wz,nr'' Detect MSBFIRST mode for SHIFTOUTif_zjmp #MSBFIRST_
jmp #loop '' Go wait for next command'------------------------------------------------------------------------------------------------------------------------------
SHIFTIN_ ''SHIFTIN Entrymov t4, arg3 wz'' Load number of data bitsif_zjmp #Done '' '0' number of Bits = Donemov t1, #1wz'' Configure DataPinshl t1, arg0
muxzdira, t1 '' Set DataPin to an INPUTmov t2, #1wz'' Configure ClockPinshl t2, arg1 '' Set Mask test ClockState, #1wc'' Determine Starting Stateif_ncmuxzouta, t2 '' PreSet ClockPin LOWif_cmuxnzouta, t2 '' PreSet ClockPin HIGH muxnzdira, t2 '' Set ClockPin to an OUTPUTsub _MSBPRE, arg2 wz,nr'' Detect MSBPRE mode for SHIFTINif_zjmp #MSBPRE_
sub _LSBPRE, arg2 wz,nr'' Detect LSBPRE mode for SHIFTINif_zjmp #LSBPRE_
sub _MSBPOST, arg2 wz,nr'' Detect MSBPOST mode for SHIFTINif_zjmp #MSBPOST_
sub _LSBPOST, arg2 wz,nr'' Detect LSBPOST mode for SHIFTINif_zjmp #LSBPOST_
jmp #loop '' Go wait for next command'------------------------------------------------------------------------------------------------------------------------------
MSBPRE_ '' Receive Data MSBPRE
MSBPRE_Sin test t1, inawc'' Read Data Bit into 'C' flagrcl t3, #1'' rotate "C" flag into return valuecall #PreClock '' Send clock pulsedjnz t4, #MSBPRE_Sin '' Decrement t4 ; jump if not Zerojmp #Update_SHIFTIN '' Pass received data to SHIFTIN receive variable'------------------------------------------------------------------------------------------------------------------------------ 'tested OK
LSBPRE_ '' Receive Data LSBPREadd t4, #1
LSBPRE_Sin test t1, inawc'' Read Data Bit into 'C' flagrcr t3, #1'' rotate "C" flag into return valuecall #PreClock '' Send clock pulsedjnz t4, #LSBPRE_Sin '' Decrement t4 ; jump if not Zeromov t4, #32'' For LSB shift data right 32 - #Bits when donesub t4, arg3
shr t3, t4
jmp #Update_SHIFTIN '' Pass received data to SHIFTIN receive variable'------------------------------------------------------------------------------------------------------------------------------
MSBPOST_ '' Receive Data MSBPOST
MSBPOST_Sin call #PostClock '' Send clock pulsetest t1, inawc'' Read Data Bit into 'C' flagrcl t3, #1'' rotate "C" flag into return valuedjnz t4, #MSBPOST_Sin '' Decrement t4 ; jump if not Zerojmp #Update_SHIFTIN '' Pass received data to SHIFTIN receive variable'------------------------------------------------------------------------------------------------------------------------------
LSBPOST_ '' Receive Data LSBPOSTadd t4, #1
LSBPOST_Sin call #PostClock '' Send clock pulsetest t1, inawc'' Read Data Bit into 'C' flagrcr t3, #1'' rotate "C" flag into return valuedjnz t4, #LSBPOST_Sin '' Decrement t4 ; jump if not Zeromov t4, #32'' For LSB shift data right 32 - #Bits when donesub t4, arg3
shr t3, t4
jmp #Update_SHIFTIN '' Pass received data to SHIFTIN receive variable'------------------------------------------------------------------------------------------------------------------------------'tested OK
LSBFIRST_ '' Send Data LSBFIRSTmov t3, arg4 '' Load t3 with DataValue
LSB_Sout test t3, #1wc'' Test LSB of DataValuemuxcouta, t1 '' Set DataBit HIGH or LOWshr t3, #1'' Prepare for next DataBitcall #PostClock '' Send clock pulsedjnz t4, #LSB_Sout '' Decrement t4 ; jump if not Zeromov t3, #0wz'' Force DataBit LOWmuxnzouta, t1
jmp #loop '' Go wait for next command'------------------------------------------------------------------------------------------------------------------------------'tested OK
MSBFIRST_ '' Send Data MSBFIRSTmov t3, arg4 '' Load t3 with DataValuemov t5, #%1'' Create MSB mask ; load t5 with "1"shl t5, arg3 '' Shift "1" N number of bits to the left.shr t5, #1'' Shifting the number of bits left actually puts'' us one more place to the left than we want. To'' compensate we'll shift one position right.
MSB_Sout test t3, t5 wc'' Test MSB of DataValuemuxcouta, t1 '' Set DataBit HIGH or LOWshr t5, #1'' Prepare for next DataBitcall #PostClock '' Send clock pulsedjnz t4, #MSB_Sout '' Decrement t4 ; jump if not Zeromov t3, #0wz'' Force DataBit LOWmuxnzouta, t1
jmp #loop '' Go wait for next command'------------------------------------------------------------------------------------------------------------------------------'tested OK
Update_SHIFTIN
mov t1, address '' Write data back to Arg4add t1, #16'' Arg0 = #0 ; Arg1 = #4 ; Arg2 = #8 ; Arg3 = #12 ; Arg4 = #16wrlong t3, t1
add t1, #4'' Point t1 to Flag ... Arg4 + #4wrlong zero, t1 '' Clear Flag ... indicates SHIFTIN data is readyjmp #loop '' Go wait for next command'------------------------------------------------------------------------------------------------------------------------------'tested OK
PreClock
mov t2, #0nr'' Clock Pintest t2, inawz'' Read ClockPin muxzouta, t2 '' Set ClockPin to opposite of read valuecall #ClkDly
muxnzouta, t2 '' Restore ClockPin to original read valuecall #ClkDly
PreClock_ret ret'' return'------------------------------------------------------------------------------------------------------------------------------'tested OK
PostClock
mov t2, #0nr'' Clock Pintest t2, inawz'' Read ClockPincall #ClkDly
muxzouta, t2 '' Set ClockPin to opposite of read valuecall #ClkDly
muxnzouta, t2 '' Restore ClockPin to original read value
PostClock_ret ret'' return'------------------------------------------------------------------------------------------------------------------------------'tested OK
ClkDly
mov t6, ClockDelay
ClkPause djnz t6, #ClkPause
ClkDly_ret ret'------------------------------------------------------------------------------------------------------------------------------'tested OK
startup mov t7, t8 '' t7 = commandand t7, #1'' clockstate in bit 0mov ClockState, t7
mov t7, t8
shr t7, #2'' clockdelay was stored lsb bit 2and t7, #$FFmov ClockDelay, t7
wrlong zero, par'' zero commandjmp #loop
' --------------------------------------------------
Done '' Shut COG downmov t2, #0'' Preset temp variable to Zeromov t1, par'' Read the address of the first perimeteradd t1, #4'' Add offset for the second perimeter ; The 'Flag' variablewrlong t2, t1 '' Reset the 'Flag' variable to ZeroCogID t1 '' Read CogIDCOGSTOP t1 '' Stop this Cog!'------------------------------------------------------------------------------------------------------------------------------{
########################### Assembly variables ###########################
}
zero long0''constants
d0 long$200
_MSBPRE long$0'' Applies to SHIFTIN
_LSBPRE long$1'' Applies to SHIFTIN
_MSBPOST long$2'' Applies to SHIFTIN
_LSBPOST long$3'' Applies to SHIFTIN
_LSBFIRST long$4'' Applies to SHIFTOUT
_MSBFIRST long$5'' Applies to SHIFTOUT
ClockDelay long0
ClockState long0''temp variables
t1 long0'' Used for DataPin mask and COG shutdown
t2 long0'' Used for CLockPin mask and COG shutdown
t3 long0'' Used to hold DataValue SHIFTIN/SHIFTOUT
t4 long0'' Used to hold # of Bits
t5 long0'' Used for temporary data mask
t6 long0'' Used for Clock Delay
address long0'' Used to hold return address of first Argument passed
t7 long0
t8 long0
stconst long$40000
arg0 long0''arguments passed to/from high-level Spin
arg1 long0
arg2 long0
arg3 long0
arg4 long0
I've completed the code and compile (Make Project Library) part of making an SPI library that uses modified PASM from the Spin Library object SPI_Asm.spin. I still have to do the documentation and clean up (add the MIT license info).
I originally got the library working to receive data from the CMUCAM5 pixy.
The pixy does not require any SHIFTOUTs from the prop, so it is just a matter of shifting in the data as fast as possible. (and the library functions are very fast).
But I also wanted to make the library more general. I just bought the DS1620 digital thermometer that was used in the spin demo, and that is the "test harness" in the library folder. That does require sending commands to the SPI device to configure it and to get the data. I did find that I had to add some pauses between sending commands and setting the "RESET" pin to low that were not in the spin program.
Until I get the documentation done, to run the demo (libspiasm.c) use the same connections for the DS1620 as are in the SPI_Spin_demo.spin file that comes with the Prop Tool. The pin numbers are also in the c file.
I haven't had a chance to add new devices to the SPI library, but I noticed that the library attached to the previous post contained a buggy version of xSPIAsm.spin, and that it did not include my program for the MMA7455 3 axis accelerometer. So I have attached the updated library below.
It contains:
- the SPI library code and header -- spiasm.c and spiasm.h (#INCLUDE spiasm.h in the main program)
- the ASM code in -- xSPIAsm.spin (this file has to be added to each SimpleIDE Project that calls the SPI functions. This version has the MSBFIRST_ code correction.)
- the program for the DS1600 digital thermometer chip -- libspiasm.c (it was the "test harness for the library, and I need to change the name to be more descriptive).
- the program for reading the MMA7455 3 axis accelerometer -- mma7455-spi.c
- the documentation for the library
- supporting files.
I hope to find time to write the code (convert from SPIN sources) for the SCP1000 pressure sensor module. That one will be interesting since it uses one pin for Rx and one for Tx, and seems a bit more complex (different). But I haven't had a lot of quiet time lately.
I've made a function version of the MPC3208 code where main() is a demo calling the function "get3208se(channel_number)" Use Run with Terminal.
/* 3208-spi-function.c MPC3208 ADC interface using spiasm library
Function version with main() as demo
Uses pasm in xspiasm.spin, modified from SPI_Asm.spin propeller tool library object.
T Montemarano (MIT License)
The SPI device called in main() is a MPC3208 ADC.
Used wiring from Programming & Customizing the Multicore Propeller Microcontroller
page 158, but using MPC3208 ADC instead of MPC3204. (16 pin vs 14 pin device).
Note there are different device pin definitions.
*/#include"simpletools.h"// Library includes#include"spiasm.h"/* ******************************************************
Uses MPC3208 ADC as SPI device
MPC3208 pin Prop pin
CS <- Prop P2 low starts transfer, high terminates
DATA in/out <-> Prop P1 Prop out (MFIRST), Prop in (MPOST)
Clock <- Prop P0 rise then fall State = 0
*/#define cstate 0 // 0 = start clock low, 1 = start clock high#define clockd_ns 1000 // Actual delay in nanoseconds (1000ns = 1 usec), not less than 300ns// ClockDelay, actual clock delay = 300ns + (cdelay-1) * 50ns// e.g. cdelay of 15 gives actual clock delay = 1 usec// cdelay = ((clockd_ns) - 250ns)) / 50ns// e.g. for 2 usec (i.e. 2000 ns): cdelay = 35// ** Propeller pins #define CS 2#define IOPIN 1#define CLKPIN 0#define VREF 5 // for 5 volt Vdd and Vref For lower Vdd voltage may have to set clock_ns slower#define MAXCHAN 3 // max channel number 0 to 7 (ch 0 & 1 = pots, 2 = 3.3v buss, 3 = Vss)intget3208se(int chnum); // function prototype for single ended 3208 readspia_t *spia;
intmain()// Main function{
int i;
int adcraw;
int voltsin;
high(CS); // disable 3208 data transfer
spia = spi_start(clockd_ns, cstate); // Launch, get handles, set ClockDelay & ClockState while(1) // bb
{
for(i = 0; i <= MAXCHAN; i++) // aa
{
int adcraw = get3208se(i); // read channel i// data handling & printout
voltsin = (adcraw * VREF * 1000) / 4095;
printi("Channel %d: raw = %d, %d.%d volts\n", i, adcraw, (voltsin/1000), voltsin - (voltsin/1000) *1000);
pause(10);
} // end aa
printi("\n");
pause(800);
} // end bb
} // end mainintget3208se(int chnum){
// ** declare 3208 Command values here - start bit, modeint startbit = 0b10000;
int mode_se = 0b01000;
// channel number = 0 to 7 in chnum// ** end of command values int cmd3208 = 0;
int rawval = 0;
high(CS);
pause(5);
cmd3208 = (startbit | mode_se | chnum) & 0b11111; // build 5 bit 3208 command
low(CS); // activate 3208 ADC
pause(1);
spi_out(spia, IOPIN, CLKPIN, MFIRST, 5, cmd3208); // start conversion hi, mode, channel(3bits)
spi_out(spia, IOPIN, CLKPIN, MFIRST, 1, 0); // send don't care bit
rawval = spi_in(spia, IOPIN, CLKPIN, MPOST, 13); // read null & 12 bit value
pause(5);
high(CS); // release 3208return rawval;
}
I’ve made significant changes to the LIBSPIASM library.
Note that programs that used the libraries in the LIBSPIASM.ZIP file of post 67 will NOT work with the new version.
Originally, I trasferred parameters like pin numbers to the functions using Globals. (Note in the post above that the main 3208 program gets the data into adcraw by:
int adcraw = get3208se(i); // read channel i
The only parameter directly passed in the function call is the ADC channel number.
But then I realized that one of the purposes of an SPI bus is to attach a number of devices and select each one using its chip select protocol. And sometimes there will be a number of the same type of devices (for example DS1620 digital thermometers) connected to the bus. Passing parameters using globals won’t work.
To enable the use of multiple devices, it was necessary to pass all the needed parameters to the library function in the call to the function.
For example the code above becomes:
int adcraw = get_3208se(spia_1, IOPIN3208, CLKPIN3208, CS3208, i); // read channel i
The parameters needed and the returned values are listed in the library documentation.
Note that a number of the same or different types of devices can be used with only one call to the "start" function. The advantage of doing that is that only one extra cog is used. (Each call to "start" starts a new cog.) One limitation is that all the devices used with that "start" (spia_t variable) need to have the same timing characteristics (clock delay timing and clock state).
In addition I changed the names of the functions to be in accordance with the guidelines in the Simple Libraries Tutorial.
libspiasm v2.zip contains the library and documentation. It should be unzipped into a Learn Simple libraries folder
(for example: SimpleIDE\Learn\Simple Libraries\My Libraries\libspiasm)
There is a documentation file and the libraries:
libspiasm – the test harness for the library, and used to build libraries for new devices
libSPI-DS1620.c -- for DS1620 digital thermometer
libSPI-MCP3208.c -- for MCP 3208, 8 channel 12 bit ADC used in SE mode
libSPI-MMA7455.c -- for MMA7455 accelerometer – just basic for reading the 3 axes
libSPI-SCP1000.c -- for SCP1000 absolute pressure sensor
The basic library functions (spi_start, spi_stop, spi_out, and spi_in) were not changed and can be called directly rather than using the device functions for other devices or for using the advanced features of the devices.
The other zip is a group of 6 simple demo programs that use the libraries.
They include:
the MCP3208,
the DS1620,
the MCP3208 and DS1620 using the same cog (only 1 call to “start”) and different I/O pins
the MCP3208 and DS1620 using common I/O pins with separate Chip Select pins
the MMA7455 accelerometer
the SCP1000 absolute pressure sensor.
When you load the demos into SimpleIDE, if it doesn't build, you may need to use the project command to add the library.
Since this is a learning experience for me, I'd appreciate any comments.
I am not sure if the SCP1000 code works. I get one reading from the sensor, but the as I change the height of the sensor, the pressure reading stays the same.
Comments
At the beginning of the pasm it tests for nonzero command.
So right after the "if_z jmp #loop" I would add the following.
mov t7, t1 '' move 'command' to new variable t7 mov t8, t1 '' make a copy and t7, #$40000 wz '' C program defines command 4 <<16 for start up If_nz jmp #startup
Put startup at end of current code (but before 'done').startup mov t7, t8 '' make t7 whole and t7 , #1 " first bit of command is Clockstate mov ClockState, t7 mov t7, t8 shr t7, #2 " C packed ClockDelay in command by shifting ClockDelay << 2 and t7, #$FF mov ClockDelay, t7 wrlong zero, par ''set command back to zero jmp #loop
define after arg4 the followingt7 long 0 t8 long 0
In the C program, in the start function, after starting the cog, but before the return I would add the followingdevice->command = (4 << 16) | ( clkdly << 2) | ( clkst);
and all of the needed declarations.Sorry for the poor spacing, but I'm doing this on a tablet.
Comment please.
Thanks
Tom
dat org 0 ws2812 jmp #ws2812_cont resettix long 0 ' frame reset timing bit0hi long 0 ' bit0 high timing bit0lo long 0 ' bit0 low timing bit1hi long 0 ' bit1 high timing bit1lo long 0 ' bit1 low timing ws2812_cont mov t1, par ' get the pin number rdlong t2, t1 mov txmask, #1 ' create mask for tx shl txmask, t2 andn outa, txmask ' set to output low or dira, txmask add t1, #4 rdlong hubpntr, t1 ' get the buffer address add t1, #4 rdlong ledcount, t1 ' get the led count mov t2, #0 ' init is done wrlong t2, t1
You then access the fields of the PASM code using a structure like this:// driver header structure typedef struct { uint32_t jmp_inst; uint32_t resettix; uint32_t bit0hi; uint32_t bit0lo; uint32_t bit1hi; uint32_t bit1lo; } ws2812_hdr;
I had already modified the spin file's pasm and once I fixed a couple of things, (like trying to use $40000 as an immediate), I tried it and it did work. I am thinking about trying to write a version, and would use your suggestion.
It is very fast getting 14+ blocks of Pixy data per frame, which is much faster than the spin or simpleIDE library versions.
My next step in this exercise is to put all of the spi constants (MSPRE, etc.) into the program. (The pixy only used MSPRE which = 2 in the original spin program), and the separate the parts into a library.
The revised C program and pasm are listed below, and the spin file is attached.
/* spipasm 3 - a fast spin interface library project Updated to use pasm to set ClockDelay and ClockState Use pasm modified from SPI_Asm.spin propeller tool library object. T Montemarano (with a lot of help) NOTES: Uses spin file xSPIAsm.spin, This version does run correctly. The SPI device called in main() is a Pixy CMUCAM5. It does not required a start command since it always transmits data at 1usec. It should be possible to change main to use other spi devices like the DS1620 used in the spi spin demo. This version uses the same calls as the SPI_Asm.spin library object. device->command is either 0 or packed with 2 or 3 numbers to be used by pasm. command = 0 -- pasm in idle loop in spipasm_start, the number 4 is shifted left 16 bits to indicate 'startup' the ClockDelay value is shifted left 2 bits the ClockState value is in bit 0. All 3 values are or'd. in spipasm_SHIFTIN the number 2 is shifted left 16 bits, this is or'd with the address of the Dpin in spipasm_SHIFTOUT, the number 1 is shifted left 16 bits, and or'd with the address of the Dpin */ #include "simpletools.h" // Library includes typedef struct spipasm_struct // Structure contains varaibles { // for cogs to share + cog & stack volatile int command; int Dpin; int Cpin; volatile int Mode; volatile int Bits; volatile int Value; volatile int Flag; int cog; // Remembers cog for spiasm_stop } spia_t; // Data type for struct int pixydata[400]; int clkst = 0; // 0 = start clock low, 1 = start clock high int clkdly = 15; // ClockDelay, actual clock delay = 300ns + (clkdly-1) * 50ns // clkdly = 15 gives clock delay = 1 usec // function prototypes spia_t *spipasm_start(int clkdly, int clkst); void spipasm_stop(spia_t *device); void spipasm_SHIFTOUT(spia_t *device, int DQ, int CLK, int MD, int BIT, int VLU); int spipasm_SHIFTIN(spia_t *device,int DQ, int CLK, int MD, int BIT); void spipasm_setcommand(spia_t *device, int cmd, int *argptr); /* libblinkpasm.c Test harness for the spipasm library. */ // #include "spipasm.h" spia_t *spia; int main() // Main function { int px; // Put demo code here spia = spipasm_start(clkdly, clkst); // Launch, get handles int i = 1; while(i<398) // fill pixydata array with spi bytes { // Pixy SPI interface continuously transmits data (no starting or stopping it) // Pixy data out rate is 1usec // Pixy SPI data out -> Prop P0, Pixy Clock -> Prop P2 // spipasm_shiftin(Dpin, Cpin, Mode, Bits) pixydata[i] = spipasm_SHIFTIN(spia, 0, 2, 0, 8); // Mode 0 = MSBPRE i++; } i = 1; while(i<398) // write pixydata array { // printi(" i = %d color = %x\n", i, pixydata[i]); printi("%d\n", pixydata[i]); i++; } spipasm_stop(spia); } // These are the actual functions // **************************************** spia_t *spipasm_start(int clkd, int clks) { spia_t *device; // Declare spipasm pointer device = (void *) malloc(sizeof(spia_t)); // Allocate memory for it if(device->cog == 0) { device->command = 0; // pasm stays in waiting loop till non zero extern int binary_xSPIAsm_dat_start[]; device->cog = 1 + cognew((void*)binary_xSPIAsm_dat_start, (void*)device); } device->command = (4 << 16) | (clkd << 2) | clks ; // pasm reads command, sets ClockDelay, ClockState while(device->command); // wait till pasm resets command to zero return device; // Return pointer to structure } // ************************************ void spipasm_stop(spia_t *device) { if(device->cog > 0) // If cog running { cogstop(device->cog - 1); // Shut down cog device->cog = 0; // Clear cog varaible free(device); // Release allocated memory } } // ************************************ void spipasm_SHIFTOUT(spia_t *device, int DQ, int CLK, int MD, int BIT, int VLU) { device->Dpin = DQ; // load variable values for pasm device->Cpin = CLK; device->Mode = MD; device->Bits = BIT; device->Value = VLU; spipasm_setcommand(spia,1, &device->Dpin); } // ************************************ int spipasm_SHIFTIN(spia_t *device, int DQ, int CLK, int MD, int BIT) { device->Dpin = DQ; device->Cpin = CLK; device->Mode = MD; device->Bits = BIT; device->Flag = 1; spipasm_setcommand(spia, 2, &device->Dpin); while(device->Flag); // pasm sets Flag =0 when finished reading all bits in Value return device->Value; } // ************************************ void spipasm_setcommand(spia_t *device, int cmd, int *argptr) { device->command = (int) argptr | (cmd << 16); while(device->command); }
DAT org ' '' SPI Engine - main loop ' loop rdlong t1,par wz ''wait for command if_z jmp #loop mov t7, t1 '' command to t7 mov t8, t7 '' copy command and t7, stconst wz '' test for startup if_nz jmp #startup movd :arg,#arg0 ''get 5 arguments ; arg0 to arg4 mov t2,t1 '' │ mov t3,#5 ''───┘ :arg rdlong arg0,t2 add :arg,d0 add t2,#4 djnz t3,#:arg mov address,t1 ''preserve address location for passing ''variables back to Spin language. wrlong zero,par ''zero command to signify command received ror t1,#16+2 ''lookup command address add t1,#jumps movs :table,t1 rol t1,#2 shl t1,#3 :table mov t2,0 shr t2,t1 and t2,#$FF jmp t2 ''jump to command jumps byte 0 ''0 byte SHIFTOUT_ ''1 byte SHIFTIN_ ''2 byte NotUsed_ ''3 NotUsed_ jmp #loop '################################################################################################################ 'tested OK SHIFTOUT_ ''SHIFTOUT Entry mov t4, arg3 wz '' Load number of data bits if_z jmp #Done '' '0' number of Bits = Done mov t1, #1 wz '' Configure DataPin shl t1, arg0 muxz outa, t1 '' PreSet DataPin LOW muxnz dira, t1 '' Set DataPin to an OUTPUT mov t2, #1 wz '' Configure ClockPin shl t2, arg1 '' Set Mask test ClockState, #1 wc '' Determine Starting State if_nc muxz outa, t2 '' PreSet ClockPin LOW if_c muxnz outa, t2 '' PreSet ClockPin HIGH muxnz dira, t2 '' Set ClockPin to an OUTPUT sub _LSBFIRST, arg2 wz,nr '' Detect LSBFIRST mode for SHIFTOUT if_z jmp #LSBFIRST_ sub _MSBFIRST, arg2 wz,nr '' Detect MSBFIRST mode for SHIFTOUT if_z jmp #MSBFIRST_ jmp #loop '' Go wait for next command '------------------------------------------------------------------------------------------------------------------------------ SHIFTIN_ ''SHIFTIN Entry mov t4, arg3 wz '' Load number of data bits if_z jmp #Done '' '0' number of Bits = Done mov t1, #1 wz '' Configure DataPin shl t1, arg0 muxz dira, t1 '' Set DataPin to an INPUT mov t2, #1 wz '' Configure ClockPin shl t2, arg1 '' Set Mask test ClockState, #1 wc '' Determine Starting State if_nc muxz outa, t2 '' PreSet ClockPin LOW if_c muxnz outa, t2 '' PreSet ClockPin HIGH muxnz dira, t2 '' Set ClockPin to an OUTPUT sub _MSBPRE, arg2 wz,nr '' Detect MSBPRE mode for SHIFTIN if_z jmp #MSBPRE_ sub _LSBPRE, arg2 wz,nr '' Detect LSBPRE mode for SHIFTIN if_z jmp #LSBPRE_ sub _MSBPOST, arg2 wz,nr '' Detect MSBPOST mode for SHIFTIN if_z jmp #MSBPOST_ sub _LSBPOST, arg2 wz,nr '' Detect LSBPOST mode for SHIFTIN if_z jmp #LSBPOST_ jmp #loop '' Go wait for next command '------------------------------------------------------------------------------------------------------------------------------ MSBPRE_ '' Receive Data MSBPRE MSBPRE_Sin test t1, ina wc '' Read Data Bit into 'C' flag rcl t3, #1 '' rotate "C" flag into return value call #PreClock '' Send clock pulse djnz t4, #MSBPRE_Sin '' Decrement t4 ; jump if not Zero jmp #Update_SHIFTIN '' Pass received data to SHIFTIN receive variable '------------------------------------------------------------------------------------------------------------------------------ 'tested OK LSBPRE_ '' Receive Data LSBPRE add t4, #1 LSBPRE_Sin test t1, ina wc '' Read Data Bit into 'C' flag rcr t3, #1 '' rotate "C" flag into return value call #PreClock '' Send clock pulse djnz t4, #LSBPRE_Sin '' Decrement t4 ; jump if not Zero mov t4, #32 '' For LSB shift data right 32 - #Bits when done sub t4, arg3 shr t3, t4 jmp #Update_SHIFTIN '' Pass received data to SHIFTIN receive variable '------------------------------------------------------------------------------------------------------------------------------ MSBPOST_ '' Receive Data MSBPOST MSBPOST_Sin call #PostClock '' Send clock pulse test t1, ina wc '' Read Data Bit into 'C' flag rcl t3, #1 '' rotate "C" flag into return value djnz t4, #MSBPOST_Sin '' Decrement t4 ; jump if not Zero jmp #Update_SHIFTIN '' Pass received data to SHIFTIN receive variable '------------------------------------------------------------------------------------------------------------------------------ LSBPOST_ '' Receive Data LSBPOST add t4, #1 LSBPOST_Sin call #PostClock '' Send clock pulse test t1, ina wc '' Read Data Bit into 'C' flag rcr t3, #1 '' rotate "C" flag into return value djnz t4, #LSBPOST_Sin '' Decrement t4 ; jump if not Zero mov t4, #32 '' For LSB shift data right 32 - #Bits when done sub t4, arg3 shr t3, t4 jmp #Update_SHIFTIN '' Pass received data to SHIFTIN receive variable '------------------------------------------------------------------------------------------------------------------------------ 'tested OK LSBFIRST_ '' Send Data LSBFIRST mov t3, arg4 '' Load t3 with DataValue LSB_Sout test t3, #1 wc '' Test LSB of DataValue muxc outa, t1 '' Set DataBit HIGH or LOW shr t3, #1 '' Prepare for next DataBit call #PostClock '' Send clock pulse djnz t4, #LSB_Sout '' Decrement t4 ; jump if not Zero mov t3, #0 wz '' Force DataBit LOW muxnz outa, t1 jmp #loop '' Go wait for next command '------------------------------------------------------------------------------------------------------------------------------ 'tested OK MSBFIRST_ '' Send Data MSBFIRST mov t3, arg4 '' Load t3 with DataValue mov t5, #%1 '' Create MSB mask ; load t5 with "1" shl t5, arg3 '' Shift "1" N number of bits to the left. shr t5, #1 '' Shifting the number of bits left actually puts '' us one more place to the left than we want. To '' compensate we'll shift one position right. MSB_Sout test t3, t5 wc '' Test MSB of DataValue muxc outa, t1 '' Set DataBit HIGH or LOW shr t5, #1 '' Prepare for next DataBit call #PostClock '' Send clock pulse djnz t4, #MSB_Sout '' Decrement t4 ; jump if not Zero mov t3, #0 wz '' Force DataBit LOW muxnz outa, t1 jmp #loop '' Go wait for next command '------------------------------------------------------------------------------------------------------------------------------ 'tested OK Update_SHIFTIN mov t1, address '' Write data back to Arg4 add t1, #16 '' Arg0 = #0 ; Arg1 = #4 ; Arg2 = #8 ; Arg3 = #12 ; Arg4 = #16 wrlong t3, t1 add t1, #4 '' Point t1 to Flag ... Arg4 + #4 wrlong zero, t1 '' Clear Flag ... indicates SHIFTIN data is ready jmp #loop '' Go wait for next command '------------------------------------------------------------------------------------------------------------------------------ 'tested OK PreClock mov t2, #0 nr '' Clock Pin test t2, ina wz '' Read ClockPin muxz outa, t2 '' Set ClockPin to opposite of read value call #ClkDly muxnz outa, t2 '' Restore ClockPin to original read value call #ClkDly PreClock_ret ret '' return '------------------------------------------------------------------------------------------------------------------------------ 'tested OK PostClock mov t2, #0 nr '' Clock Pin test t2, ina wz '' Read ClockPin call #ClkDly muxz outa, t2 '' Set ClockPin to opposite of read value call #ClkDly muxnz outa, t2 '' Restore ClockPin to original read value PostClock_ret ret '' return '------------------------------------------------------------------------------------------------------------------------------ 'tested OK ClkDly mov t6, ClockDelay ClkPause djnz t6, #ClkPause ClkDly_ret ret '------------------------------------------------------------------------------------------------------------------------------ 'tested OK startup mov t7, t8 '' t7 = command and t7, #1 '' clockstate in bit 0 mov ClockState, t7 mov t7, t8 shr t7, #2 '' clockdelay was stored lsb bit 2 and t7, #$FF mov ClockDelay, t7 wrlong zero, par '' zero command jmp #loop ' -------------------------------------------------- Done '' Shut COG down mov t2, #0 '' Preset temp variable to Zero mov t1, par '' Read the address of the first perimeter add t1, #4 '' Add offset for the second perimeter ; The 'Flag' variable wrlong t2, t1 '' Reset the 'Flag' variable to Zero CogID t1 '' Read CogID COGSTOP t1 '' Stop this Cog! '------------------------------------------------------------------------------------------------------------------------------ { ########################### Assembly variables ########################### } zero long 0 ''constants d0 long $200 _MSBPRE long $0 '' Applies to SHIFTIN _LSBPRE long $1 '' Applies to SHIFTIN _MSBPOST long $2 '' Applies to SHIFTIN _LSBPOST long $3 '' Applies to SHIFTIN _LSBFIRST long $4 '' Applies to SHIFTOUT _MSBFIRST long $5 '' Applies to SHIFTOUT ClockDelay long 0 ClockState long 0 ''temp variables t1 long 0 '' Used for DataPin mask and COG shutdown t2 long 0 '' Used for CLockPin mask and COG shutdown t3 long 0 '' Used to hold DataValue SHIFTIN/SHIFTOUT t4 long 0 '' Used to hold # of Bits t5 long 0 '' Used for temporary data mask t6 long 0 '' Used for Clock Delay address long 0 '' Used to hold return address of first Argument passed t7 long 0 t8 long 0 stconst long $40000 arg0 long 0 ''arguments passed to/from high-level Spin arg1 long 0 arg2 long 0 arg3 long 0 arg4 long 0
xSPIAsm - Archive [Date 2014.09.28 Time 15.46].zip
I originally got the library working to receive data from the CMUCAM5 pixy.
The pixy does not require any SHIFTOUTs from the prop, so it is just a matter of shifting in the data as fast as possible. (and the library functions are very fast).
But I also wanted to make the library more general. I just bought the DS1620 digital thermometer that was used in the spin demo, and that is the "test harness" in the library folder. That does require sending commands to the SPI device to configure it and to get the data. I did find that I had to add some pauses between sending commands and setting the "RESET" pin to low that were not in the spin program.
Until I get the documentation done, to run the demo (libspiasm.c) use the same connections for the DS1620 as are in the SPI_Spin_demo.spin file that comes with the Prop Tool. The pin numbers are also in the c file.
The zipped library is attached.
Tom
It contains:
- the SPI library code and header -- spiasm.c and spiasm.h (#INCLUDE spiasm.h in the main program)
- the ASM code in -- xSPIAsm.spin (this file has to be added to each SimpleIDE Project that calls the SPI functions. This version has the MSBFIRST_ code correction.)
- the program for the DS1600 digital thermometer chip -- libspiasm.c (it was the "test harness for the library, and I need to change the name to be more descriptive).
- the program for reading the MMA7455 3 axis accelerometer -- mma7455-spi.c
- the documentation for the library
- supporting files.
I hope to find time to write the code (convert from SPIN sources) for the SCP1000 pressure sensor module. That one will be interesting since it uses one pin for Rx and one for Tx, and seems a bit more complex (different). But I haven't had a lot of quiet time lately.
Tom
libspiasm.zip
Tom
/* 3208-spi.c 3208 ADC interface using spiasm library Uses pasm in xspiasm.spin, modified from SPI_Asm.spin propeller tool library object. T Montemarano (MIT License) The SPI device called in main() is a 3208 ADC. Used wiring from Programming & Customizing the Multicore Propeller Microcontroller page 158, but using 3208 ADC. (16 pin vs 14 pin device). Note different device pin definitions. */ #include "simpletools.h" // Library includes #include "spiasm.h" /* ****************************************************** Uses 3208 ADC as SPI device 3208 pin Prop pin CS <- Prop P2 low starts transfer, high terminates DATA in/out <-> Prop P1 Prop out (MFIRST), Prop in (MPOST) Clock <- Prop P0 rise then fall State = 0 */ #define cstate 0 // 0 = start clock low, 1 = start clock high #define clockd_ns 1000 // Actual delay in nanoseconds (1000ns = 1 usec), not less than 300ns // ClockDelay, actual clock delay = 300ns + (cdelay-1) * 50ns // e.g. cdelay of 15 gives actual clock delay = 1 usec // cdelay = ((clockd_ns) - 250ns)) / 50ns // e.g. for 2 usec (i.e. 2000 ns): cdelay = 35 // ** Propeller pins #define CS 2 #define IOPIN 1 #define CLKPIN 0 #define VREF 5 // for 5 volt Vdd and Vref For lower Vdd voltage may have to set clock_ns slower #define MAXCHAN 3 // max channel number (ch 0 & 1 = pots, 2 = 3.3v buss, 3 = Vss) spia_t *spia; int main() // Main function { int i; // ** declare 3208 Command values here - mode, channel int startbit = 0b10000; int mode_se = 0b01000; int ch[8]; ch[0] = 0b00000; ch[1] = 0b00001; ch[2] = 0b00010; ch[3] = 0b00011; ch[4] = 0b00100; ch[5] = 0b00101; ch[6] = 0b00110; ch[7] = 0b00111; // ** end of command values int cmd3208; int adcraw; // raw value from ADC high(CS); // disable 3208 data transfer spia = spi_start(clockd_ns, cstate); // Launch, get handles, set ClockDelay & ClockState while(1) // bb { for(i = 0; i <= MAXCHAN; i++) // aa { // read channel i cmd3208 = (startbit | mode_se | ch[i]) & 0b11111; // build 3208 command low(CS); // activate 3208 ADC pause(1); spi_out(spia, IOPIN, CLKPIN, MFIRST, 5, cmd3208); // start conversion hi, mode, channel(3bits) spi_out(spia, IOPIN, CLKPIN, MFIRST, 1, 0); // send don't care bit adcraw = spi_in(spia, IOPIN, CLKPIN, MPOST, 13); // read null & 12 bit value pause(5); high(CS); // release 3208 // put data handling & printout here int voltsin = (adcraw * VREF * 1000) / 4095; printi("Channel %d: raw = %d, %d.%d volts\n", i, adcraw, (voltsin/1000), voltsin - (voltsin/1000) *1000); cmd3208 = 0; pause(10); } // end aa printi("\n"); pause(800); } // end bb } // end main
/* 3208-spi-function.c MPC3208 ADC interface using spiasm library Function version with main() as demo Uses pasm in xspiasm.spin, modified from SPI_Asm.spin propeller tool library object. T Montemarano (MIT License) The SPI device called in main() is a MPC3208 ADC. Used wiring from Programming & Customizing the Multicore Propeller Microcontroller page 158, but using MPC3208 ADC instead of MPC3204. (16 pin vs 14 pin device). Note there are different device pin definitions. */ #include "simpletools.h" // Library includes #include "spiasm.h" /* ****************************************************** Uses MPC3208 ADC as SPI device MPC3208 pin Prop pin CS <- Prop P2 low starts transfer, high terminates DATA in/out <-> Prop P1 Prop out (MFIRST), Prop in (MPOST) Clock <- Prop P0 rise then fall State = 0 */ #define cstate 0 // 0 = start clock low, 1 = start clock high #define clockd_ns 1000 // Actual delay in nanoseconds (1000ns = 1 usec), not less than 300ns // ClockDelay, actual clock delay = 300ns + (cdelay-1) * 50ns // e.g. cdelay of 15 gives actual clock delay = 1 usec // cdelay = ((clockd_ns) - 250ns)) / 50ns // e.g. for 2 usec (i.e. 2000 ns): cdelay = 35 // ** Propeller pins #define CS 2 #define IOPIN 1 #define CLKPIN 0 #define VREF 5 // for 5 volt Vdd and Vref For lower Vdd voltage may have to set clock_ns slower #define MAXCHAN 3 // max channel number 0 to 7 (ch 0 & 1 = pots, 2 = 3.3v buss, 3 = Vss) int get3208se(int chnum); // function prototype for single ended 3208 read spia_t *spia; int main() // Main function { int i; int adcraw; int voltsin; high(CS); // disable 3208 data transfer spia = spi_start(clockd_ns, cstate); // Launch, get handles, set ClockDelay & ClockState while(1) // bb { for(i = 0; i <= MAXCHAN; i++) // aa { int adcraw = get3208se(i); // read channel i // data handling & printout voltsin = (adcraw * VREF * 1000) / 4095; printi("Channel %d: raw = %d, %d.%d volts\n", i, adcraw, (voltsin/1000), voltsin - (voltsin/1000) *1000); pause(10); } // end aa printi("\n"); pause(800); } // end bb } // end main int get3208se(int chnum) { // ** declare 3208 Command values here - start bit, mode int startbit = 0b10000; int mode_se = 0b01000; // channel number = 0 to 7 in chnum // ** end of command values int cmd3208 = 0; int rawval = 0; high(CS); pause(5); cmd3208 = (startbit | mode_se | chnum) & 0b11111; // build 5 bit 3208 command low(CS); // activate 3208 ADC pause(1); spi_out(spia, IOPIN, CLKPIN, MFIRST, 5, cmd3208); // start conversion hi, mode, channel(3bits) spi_out(spia, IOPIN, CLKPIN, MFIRST, 1, 0); // send don't care bit rawval = spi_in(spia, IOPIN, CLKPIN, MPOST, 13); // read null & 12 bit value pause(5); high(CS); // release 3208 return rawval; }
Note that programs that used the libraries in the LIBSPIASM.ZIP file of post 67 will NOT work with the new version.
Originally, I trasferred parameters like pin numbers to the functions using Globals. (Note in the post above that the main 3208 program gets the data into adcraw by:
int adcraw = get3208se(i); // read channel i
The only parameter directly passed in the function call is the ADC channel number.
But then I realized that one of the purposes of an SPI bus is to attach a number of devices and select each one using its chip select protocol. And sometimes there will be a number of the same type of devices (for example DS1620 digital thermometers) connected to the bus. Passing parameters using globals won’t work.
To enable the use of multiple devices, it was necessary to pass all the needed parameters to the library function in the call to the function.
For example the code above becomes:
int adcraw = get_3208se(spia_1, IOPIN3208, CLKPIN3208, CS3208, i); // read channel i
The parameters needed and the returned values are listed in the library documentation.
Note that a number of the same or different types of devices can be used with only one call to the "start" function. The advantage of doing that is that only one extra cog is used. (Each call to "start" starts a new cog.) One limitation is that all the devices used with that "start" (spia_t variable) need to have the same timing characteristics (clock delay timing and clock state).
In addition I changed the names of the functions to be in accordance with the guidelines in the Simple Libraries Tutorial.
I have attached 2 zips.
demo-spi lib functions.zip
libspiasm v2.zip
libspiasm v2.zip contains the library and documentation. It should be unzipped into a Learn Simple libraries folder
(for example: SimpleIDE\Learn\Simple Libraries\My Libraries\libspiasm)
There is a documentation file and the libraries:
libspiasm – the test harness for the library, and used to build libraries for new devices
libSPI-DS1620.c -- for DS1620 digital thermometer
libSPI-MCP3208.c -- for MCP 3208, 8 channel 12 bit ADC used in SE mode
libSPI-MMA7455.c -- for MMA7455 accelerometer – just basic for reading the 3 axes
libSPI-SCP1000.c -- for SCP1000 absolute pressure sensor
The basic library functions (spi_start, spi_stop, spi_out, and spi_in) were not changed and can be called directly rather than using the device functions for other devices or for using the advanced features of the devices.
The other zip is a group of 6 simple demo programs that use the libraries.
They include:
the MCP3208,
the DS1620,
the MCP3208 and DS1620 using the same cog (only 1 call to “start”) and different I/O pins
the MCP3208 and DS1620 using common I/O pins with separate Chip Select pins
the MMA7455 accelerometer
the SCP1000 absolute pressure sensor.
When you load the demos into SimpleIDE, if it doesn't build, you may need to use the project command to add the library.
Since this is a learning experience for me, I'd appreciate any comments.
Tom
Tom