I am a beginner level coder and the following code is for pic32mx320f128l which uses 32 bits at a time. What changes do i need to make in this code to make it work for f28069 which takes only 16 bits at a time. The protocol used is as follows : first 32 bits consists of the command and reg address and next 32 consists of the data to be read or write. Now i need to break it into 4 sets of 16 bits : first the command then the reg address the the first 16 bits of data and then other 16 bits. Can anyone help with the coding part ?
This is the code :
/
/* Adds support for PIC32 Peripheral library functions and macros */
#include <plib.h>
#include "idalib32.h"
// for slave comm.
#include "Axis32.h"
// Configuration Bits
#pragma config FNOSC = FRCPLL // Oscillator Selection
#pragma config FPLLIDIV = DIV_2 // PLL Input Divider (PIC32 Starter Kit: use divide by 2 only)
#pragma config FPLLMUL = MUL_20 // PLL Multiplier
#pragma config FPLLODIV = DIV_1 // PLL Output Divider
#pragma config FPBDIV = DIV_1 // Peripheral Clock divisor
#pragma config FWDTEN = OFF // Watchdog Timer
#pragma config WDTPS = PS1 // Watchdog Timer Postscale
#pragma config FCKSM = CSDCMD // Clock Switching & Fail Safe Clock Monitor
#pragma config OSCIOFNC = OFF // CLKO Enable
#pragma config POSCMOD = XT // Primary Oscillator
#pragma config IESO = OFF // Internal/External Switch-over
#pragma config FSOSCEN = OFF // Secondary Oscillator Enable
#pragma config CP = OFF // Code Protect
#pragma config BWP = OFF // Boot Flash Write Protect
#pragma config PWP = OFF // Program Flash Write Protect
#pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select
#pragma config DEBUG = OFF // Debugger Disabled for Starter Kit
// application defines
#define SYS_FREQ (80000000)
#define IsBitSet(x,y) ((x & lMasks[y]) ? 1 : 0 )
// prototype
void DelayMs(unsigned int);
void SpiInitDevice(SpiChannel chn, int isMaster, int frmEn, int frmMaster);
void DelayMicros(unsigned int msec) ;
short ConsoleScreen(void) ;
#define SC04USLV_RDCMD 0x30
#define SC04USLV_WRCMD 0x31
#define SC04USLV_LATCMD 0x32
#define SC04USLV_DUMMY 0x55
BOOL LowToHigh(long lValOld,long lValNew, int nBit) ;
BOOL HighToLow(long lValOld,long lValNew, int nBit) ;
// global variables for spi comm.
char cCmd ; // command got
unsigned short nRegAddr ;
// global variables, shared with SPI interrupt
long lSetEncPos ;
BOOL bToPresetEnc ;
long lSetCtrlReg ;
BOOL bCtrlSet ;
long lMasks[32] ;
long lFWVersion = 0x100 ;
float rNewSpeed ;
BOOL bNewSpeedSet ;
long lDebug ;
// blink_leds application code
int main(void)
{
int i1,i2,i3 ;
lichar li1,li2 ;
long lOldCtrlReg ;
long lTmp ;
short LimitStatus[3] ;
long lTmpLimit[3] ;
SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
// enable device multi-vector interrupts
INTEnableSystemMultiVectoredInt();
for (i1=0;i1<32;i1++)
{
lMasks[i1] = 0x01L << i1 ;
}
// seutp the SPI first
SpiInitDevice(SPI_CHANNEL2,0,0,0) ;
cCmd = -1 ;
// set up interrupt for spi, slave
IEC1CLR=0x000000E0; // disable all SPI interrupts
SPI2CONCLR = 0x00008000 ; // stops the spi
lTmp = SPI2BUF; // clears the receive buffer
IFS1CLR=0x000000E0; // clear any existing event
IPC7CLR=0x1f000000; // clear the priority
IPC7SET=0x0d000000; // Set IPL=3, Subpriority 1
IEC1SET=0x00000080; // Enable RX
SPI2CONSET = 0x00008000 ; // enable spi again
// initialize the stepper
InitStepper() ;
bToPresetEnc = 0 ;
bCtrlSet = 0 ;
lStartSpeed = 4000 ;
lStopSpeed = 4000 ;
nRampUp = 100 ;
nRampDn = 100 ;
bStepsOver = 1 ;
LED1_MODE ;
LED1_ON ;
LED2_MODE ;
LED2_ON ;
lLimitConfig=0;
//lLimitConfig= 0x0000e0c0 ;
//bStepsOver = 0 ;
//nReqDir = 0 ;
while(1)
{
if (bCtrlSet)
{
lControlWord = lSetCtrlReg ;
bCtrlSet = 0 ;
if (lOldCtrlReg != lControlWord)
{
// D0 is not used here: direction bit
// D1: move or stop
if (LowToHigh(lOldCtrlReg,lControlWord,CTRL_MOVE_BIT))
{
// upgoing move bit
if (bStepsOver) // not moving, start axis
{
bNewSpeedSet = 0 ;
StartMovement(rReqSpeed,
lReqSteps,
IsBitSet(lControlWord,CTRL_DIR_BIT),
IsBitSet(lControlWord,CTRL_RAMP_BIT) ) ;
AXISSTAT_OUT_LOW ;
}
}
else if (HighToLow(lOldCtrlReg,lControlWord,CTRL_MOVE_BIT))
{
// downgoing move bit
if (!bStepsOver)
{
bNewSpeedSet = 0 ;
if (IsBitSet(lControlWord,CTRL_RAMP_BIT))
{
// Ramped stop
StopAxis(1) ;
}
else
{
// immediate stop
StopAxis(0) ;
AXISSTAT_OUT_HIGH ;
}
}
}
if ( LowToHigh(lOldCtrlReg,lControlWord,CTRL_CLEAR_BIT) )
{
// downgoing load bit
AXISSTAT_OUT_LOW ;
}
// D6,D7
if (IsBitSet(lControlWord,CTRL_USESERVOEN_BIT))
{
if (IsBitSet(lControlWord,CTRL_SERVOEN_BIT))
SERVOON_HIGH ;
else
SERVOON_LOW ;
}
lOldCtrlReg = lControlWord ;
}
}
// take a copy of status byte, change it and then put it back
lTmp = 0 ;
// take a copy of the limit config also
li1.lval = lLimitConfig ;
// update ramp status first
lTmp = lTmp & ~(0x03) ;
lTmp = lTmp | nRampStatus ;
LimitStatus[0] = 0 ;
LimitStatus[1] = 0 ;
LimitStatus[2] = 0 ;
lTmpLimit[0] = li1.cval[0] ;
lTmpLimit[1] = li1.cval[1] ;
lTmpLimit[2] = li1.cval[2] ;
if (PORTReadBits(IOPORT_A,BIT_2))
{
if (IsBitSet(lTmpLimit[0],LIMIT_NONC_BIT)) // NC case, limit open
{
LimitStatus[0] = 1 ;
lTmp = lTmp | STATUS_LIMIT0 ;
}
}
else
{
if (!IsBitSet(lTmpLimit[0],LIMIT_NONC_BIT)) // NO case, limit closed
{
LimitStatus[0] = 1 ;
lTmp = lTmp | STATUS_LIMIT0 ;
}
}
if (PORTReadBits(IOPORT_A,BIT_3))
{
if (IsBitSet(lTmpLimit[1],LIMIT_NONC_BIT))
{
LimitStatus[1] = 1 ;
lTmp = lTmp | STATUS_LIMIT1 ;
}
}
else
{
if (!IsBitSet(lTmpLimit[1],LIMIT_NONC_BIT))
{
LimitStatus[1] = 1 ;
lTmp = lTmp | STATUS_LIMIT1 ;
}
}
if (PORTReadBits(IOPORT_A,BIT_4))
{
if (IsBitSet(lTmpLimit[2],LIMIT_NONC_BIT))
{
LimitStatus[2] = 1 ;
lTmp = lTmp | STATUS_LIMIT2 ;
}
}
else
{
if (!IsBitSet(lTmpLimit[2],LIMIT_NONC_BIT))
{
LimitStatus[2] = 1 ;
lTmp = lTmp | STATUS_LIMIT2 ;
}
}
lStatusWord = lTmp ;
// check limits while moving
if (!bStepsOver)
{
// config 1
if (IsBitSet(lTmpLimit[0],LIMIT_ENABLE_BIT))
{
// yes enabled, check direction
if (nReqDir)
{
if ( IsBitSet(lTmpLimit[0],LIMIT_DIR_BIT) )
{
if (LimitStatus[0])
StopAxis(0) ;
}
}
else
{
if ( !IsBitSet(lTmpLimit[0],LIMIT_DIR_BIT) )
{
if (LimitStatus[0])
StopAxis(0) ;
}
}
}
// config 2
if (IsBitSet(lTmpLimit[1],LIMIT_ENABLE_BIT))
{
// yes enabled, check direction
if (nReqDir)
{
if (IsBitSet(lTmpLimit[1],LIMIT_DIR_BIT) )
{
if (LimitStatus[1])
StopAxis(0) ;
}
}
else
{
if ( !IsBitSet(lTmpLimit[1],LIMIT_DIR_BIT) )
{
if (LimitStatus[1])
StopAxis(0) ;
}
}
}
// config 3
if (IsBitSet(lTmpLimit[2],LIMIT_ENABLE_BIT))
{
// yes enabled, check direction
if (nReqDir)
{
if ( IsBitSet(lTmpLimit[2],LIMIT_DIR_BIT) )
{
if (LimitStatus[2])
StopAxis(0) ;
}
}
else
{
if ( !IsBitSet(lTmpLimit[2],LIMIT_DIR_BIT) )
{
if (LimitStatus[2])
StopAxis(0) ;
}
}
}
// Check is speed has changed
if (bNewSpeedSet)
{
// only if on flat change divisor, otherwise
// only changed req speed will do the job
if (nRampStatus == RAMPFLAT)
{
bNewSpeedSet = 0 ;
rReqSpeed = rNewSpeed ;
lDivSet = (TCYCLE/ rReqSpeed )/2.0 ;
bSpeedChanged = 1 ;
}
}
}
}
return 0;
}
/******************************************************************************
* DelayMs()
*
* This functions provides a software millisecond delay
******************************************************************************/
void DelayMs(unsigned int msec)
{
unsigned int tWait, tStart;
tWait=(SYS_FREQ/2000)*msec;
tStart=ReadCoreTimer();
while((ReadCoreTimer()-tStart)<tWait); // wait for the time to pass
}
/******************************************************************************
* DelayMicros()
*
* This functions provides a software microsecond delay
******************************************************************************/
void DelayMicros(unsigned int msec)
{
unsigned int tWait, tStart;
tWait=(SYS_FREQ/2000)*msec;
tWait = tWait/1000 ;
tStart=ReadCoreTimer();
while((ReadCoreTimer()-tStart)<tWait); // wait for the time to pass
}
void SpiInitDevice(SpiChannel chn, int isMaster, int frmEn, int frmMaster)
{
SpiOpenFlags oFlags= SPI_OPEN_MODE32 | SPI_OPEN_SSEN ;
if(isMaster)
{
oFlags|=SPI_OPEN_MSTEN;
}
if(frmEn)
{
oFlags|=SPI_OPEN_FRMEN;
if(!frmMaster)
{
oFlags|=SPI_OPEN_FSP_IN;
}
}
// divide fpb by 24: 3.33 MHz which worked with long cable and line driver
SpiChnOpen(chn, oFlags, 32);
}
void __ISR(_SPI_2_VECTOR, ipl3)__SPI2Interrupt(void)
{
ulichar liSpiVal ; // Read SPI data buffer
ulichar liSpiSendVal ;
ufloatchar fcTmp ;
liSpiVal.lval = SPI2BUF ;
if (cCmd == -1) // command byte
{
cCmd = liSpiVal.cval[3] ;
nRegAddr = liSpiVal.ival[0] ;
if (cCmd == SC04USLV_RDCMD)
{
// in read command mode, setup value to be sent
switch(nRegAddr)
{
case RDREG_VERSION:
liSpiSendVal.lval = lFWVersion ;
break ;
case RDREG_STEPSLEFT:
liSpiSendVal.lval = lStepsLeft ;
break ;
case RDREG_SPEED:
fcTmp.rval = rNowSpeed ;
liSpiSendVal.cval[0] = fcTmp.cval[0] ;
liSpiSendVal.cval[1] = fcTmp.cval[1] ;
liSpiSendVal.cval[2] = fcTmp.cval[2] ;
liSpiSendVal.cval[3] = fcTmp.cval[3] ;
break ;
case RDREG_ENCVAL:
liSpiSendVal.lval = lEncPos ;
break ;
case RDREG_CTRL:
liSpiSendVal.lval = lControlWord ;
break ;
case RDREG_STATUS:
liSpiSendVal.lval = lStatusWord ;
break ;
case RDREG_STARTSPEED:
liSpiSendVal.lval = lStartSpeed ;
break ;
case RDREG_STOPSPEED:
liSpiSendVal.lval = lStopSpeed ;
break ;
case RDREG_RAMPUP:
liSpiSendVal.lval = nRampUp ;
break ;
case RDREG_RAMPDOWN:
liSpiSendVal.lval = nRampDn ;
break ;
case RDREG_LIMITCONFIG:
liSpiSendVal.lval = lLimitConfig ;
break ;
case RDREG_NEWSPEED:
fcTmp.rval = rNewSpeed ;
liSpiSendVal.cval[0] = fcTmp.cval[0] ;
liSpiSendVal.cval[1] = fcTmp.cval[1] ;
liSpiSendVal.cval[2] = fcTmp.cval[2] ;
liSpiSendVal.cval[3] = fcTmp.cval[3] ;
break ;
case RDREG_SLVDEBUG:
liSpiSendVal.lval = ~lDebug ;
break ;
default:
liSpiSendVal.lval = liSpiVal.lval ;
break ;
}
}
else
{
// echo back the word
liSpiSendVal.lval = liSpiVal.lval ;
}
}
else if (cCmd == SC04USLV_RDCMD)
{
// already sent read response, just echo
liSpiSendVal.lval = liSpiVal.lval ;
cCmd = -1 ;
}
else if (cCmd == SC04USLV_WRCMD)
{
// in write command mode, take into register
switch(nRegAddr)
{
case WRREG_VERSION:
// not used, just echo
liSpiSendVal.lval = liSpiVal.lval ;
break ;
case WRREG_STEPSLEFT:
// later on should be able to specify serial no.
LED1_TOGGLE ;
lReqSteps = liSpiVal.lval ;
liSpiSendVal.lval = liSpiVal.lval ;
break ;
case WRREG_SPEED:
LED2_TOGGLE ;
fcTmp.cval[0] = liSpiVal.cval[0] ;
fcTmp.cval[1] = liSpiVal.cval[1] ;
fcTmp.cval[2] = liSpiVal.cval[2] ;
fcTmp.cval[3] = liSpiVal.cval[3] ;
rReqSpeed = fcTmp.rval ;
liSpiSendVal.lval = liSpiVal.lval ;
break ;
case WRREG_ENCVAL:
// preset encoder value
lSetEncPos = liSpiVal.lval ;
bToPresetEnc = 1 ;
break ;
case WRREG_CTRL:
// take new control reg value
lSetCtrlReg = liSpiVal.lval ;
bCtrlSet = 1 ;
liSpiSendVal.lval = lControlWord ;
break ;
case WRREG_STATUS:
liSpiSendVal.lval = lStatusWord ;
break ;
case WRREG_STARTSPEED:
lStartSpeed = liSpiVal.lval ;
liSpiSendVal.lval = liSpiVal.lval ; ;
break ;
case WRREG_STOPSPEED:
lStopSpeed = liSpiVal.lval ;
liSpiSendVal.lval = liSpiVal.lval ; ;
break ;
case WRREG_RAMPUP:
nRampUp = liSpiVal.lval ;
liSpiSendVal.lval = liSpiVal.lval ; ;
break ;
case WRREG_RAMPDOWN:
nRampDn = liSpiVal.lval ;
liSpiSendVal.lval = liSpiVal.lval ; ;
break ;
case WRREG_LIMITCONFIG:
lLimitConfig = liSpiVal.lval ;
liSpiSendVal.lval = lLimitConfig ;
case WRREG_NEWSPEED:
fcTmp.cval[0] = liSpiVal.cval[0] ;
fcTmp.cval[1] = liSpiVal.cval[1] ;
fcTmp.cval[2] = liSpiVal.cval[2] ;
fcTmp.cval[3] = liSpiVal.cval[3] ;
rNewSpeed = fcTmp.rval ;
liSpiSendVal.lval = liSpiVal.lval ;
bNewSpeedSet = 1 ;
break ;
case WRREG_SLVDEBUG:
liSpiSendVal.lval = 0x000000aa ;
lDebug = liSpiVal.lval ;
break ;
default:
liSpiSendVal.lval = liSpiVal.lval - 10 ;
break ;
}
// in any case echo reg addr
liSpiSendVal.lval = liSpiVal.lval - 20 ;
cCmd = -1 ;
}
else
{
cCmd = -1 ;
liSpiSendVal.lval = 0x00aa55aa ; // invalid return code
}
SPI2BUF = liSpiSendVal.lval ;
IFS1CLR = 0x000000E0; // Be sure to clear the SPI1 interrupt flags
}
BOOL LowToHigh(long lValOld,long lValNew, int nBit)
{
if ( !(IsBitSet(lValOld,nBit)) &&
IsBitSet(lValNew,nBit) )
{
// upgoing move bit
return 1 ;
}
return 0 ;
}
BOOL HighToLow(long lValOld,long lValNew, int nBit)
{
if ( IsBitSet(lValOld,nBit) &&
!(IsBitSet(lValNew,nBit)) )
{
// low going
return 1 ;
}
return 0 ;
}
/*
Master Slave Communication 32 bit:
Slave Registers:
All are 32 bit transactions
#define SC04USLV_RDCMD 0x30
#define SC04USLV_WRCMD 0x31
This command is sent first. Followed by a 0xffffffff is reading or by the actual byte.
All transactions will therefore be 2 words long
Address Map:
Write:
0: Write No effect
1: Steps to move (32 bit, int)
2: Speed to move (32 bit, float)
3: Preset Encoder Value (32 bit, int)
Preset with 0 to clear encoder
4: Control Word Write
D0-D7:
1 bit Direction : Level sensitive
1 bit Move or stop : Low to High starts movement
1 bit Ramp ON or Off : level sensitive
1 bit Clear Load : low to high clears previous load, sets status output low
1 bit Change Speed : low to high sets new speed
D8:D15: Output level control (set)
D8 : 1 use D9, 0 ignore D9
D9 : Servo status if D8
5: Status Word Write NO effect
6: StartSpeed (32 bit, int)
7: Stop Speed (32 bit, int)
8: Ramp up (32 bit, per second)
9: Ramp Down (32 bit, per second)
10: Limit Configuration
Address Map:
Read:
0: Firmware Version
1: Steps Moved
2: Current Speed (32 bit, float)
3: Read Encoder Value (32 bit, int)
4: Control Word Read
Written word as it is
5: Status Word
2 bits ramp info:
00: stop
01: ramp up
10: ramp flat
11: Ramp down
3 bits limit status
1 bit ServoStatus
D15:D31
Current Sequence Number
6: StartSpeed (32 bit, int)
Read start speed
7: Stop Speed (32 bit, int)
Read stop speed
8: Ramp up (32 bit, per second)
Read ramp up value
9: Ramp Down (32 bit, per second)
Read ramp down value
11: Read Limit Configuration
*/