diff --git a/Clock.spin b/Clock.spin new file mode 100644 index 0000000..a6f36f1 Binary files /dev/null and b/Clock.spin differ diff --git a/GDB Hello World.spin b/GDB Hello World.spin new file mode 100644 index 0000000..f8ef6bd Binary files /dev/null and b/GDB Hello World.spin differ diff --git a/GDB-API-V0.1.0.spin b/GDB-API-V0.1.0.spin new file mode 100644 index 0000000..2a5be6d Binary files /dev/null and b/GDB-API-V0.1.0.spin differ diff --git a/GDB-SerialMirror.spin b/GDB-SerialMirror.spin new file mode 100644 index 0000000..f65e0a8 Binary files /dev/null and b/GDB-SerialMirror.spin differ diff --git a/I2C_ROMEngine.spin b/I2C_ROMEngine.spin new file mode 100644 index 0000000..9254e58 --- /dev/null +++ b/I2C_ROMEngine.spin @@ -0,0 +1 @@ +{{ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // I2C Electrically Erasable Programmable Read Only Memory Engine // // Author: Kwabena W. Agyeman // Updated: 7/27/2010 // Designed For: P8X32A // Version: 1.1 // // Copyright (c) 2010 Kwabena W. Agyeman // See end of file for terms of use. // // Update History: // // v1.0 - Original release - 8/8/2009. // v1.1 - Added variable pin support - 7/27/2010. // // For each included copy of this object only one spin interpreter should access it at a time. // // Nyamekye, /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // I2C Circuit: // // 3.3V // | // R 10KOHM // | // Data Pin Number --- EEPROM SDA Pin. // // 3.3V // | // R 10KOHM // | // Clock Pin Number --- EEPROM SCL Pin. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }} PUB readByte(EEPROMaddress) '' 18 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Reads a byte from the EEPROM. It is recommended to read the byte on a byte boundary. '' // '' // Returns the byte on success and false on failure. Could return a byte of value 0. '' // '' // EEPROMaddress - Starting byte address of the data to access. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// result &= readPage(EEPROMaddress, @result, 1) PUB writeByte(EEPROMaddress, value) '' 19 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Writes a byte to the EEPROM. It is recommended to write the byte on a byte boundary. '' // '' // Returns true on success and false on failure. '' // '' // EEPROMaddress - Starting byte address of the data to access. '' // Value - Value to write to the EEPROM. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// return writePage(EEPROMaddress, @value, 1) PUB readWord(EEPROMaddress) '' 18 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Reads a word from the EEPROM. It is recommended to read the word on a word boundary. '' // '' // Returns the word on success and false on failure. Could return a word of value 0. '' // '' // EEPROMaddress - Starting byte address of the data to access. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// result &= readPage(EEPROMaddress, @result, 2) PUB writeWord(EEPROMaddress, value) '' 19 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Writes a word to the EEPROM. It is recommended to write the word on a word boundary. '' // '' // Returns true on success and false on failure. '' // '' // EEPROMaddress - Starting byte address of the data to access. '' // Value - Value to write to the EEPROM. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// return writePage(EEPROMaddress, @value, 2) PUB readLong(EEPROMaddress) '' 18 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Reads a long from the EEPROM. It is recommended to read the long on a long boundary. '' // '' // Returns the long on success and false on failure. Could return a long of value 0. '' // '' // EEPROMaddress - Starting byte address of the data to access. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// result &= readPage(EEPROMaddress, @result, 4) PUB writeLong(EEPROMaddress, value) '' 19 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Writes a long to the EEPROM. It is recommended to write the long on a long boundary. '' // '' // Returns true on success and false on failure. '' // '' // EEPROMaddress - Starting byte address of the data to access. '' // Value - Value to write to the EEPROM. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// return writePage(EEPROMaddress, @value, 4) PUB readPage(EEPROMaddress, RAMaddress, byteCount) '' 14 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Reads bytes from the EEPROM. Uses a 19 bit addressing scheme which can acess multiple EERPOMs on a bus. '' // '' // This rountine can only read from the EEPROM selected. Any reads past that EEPROM will warp arround. '' // '' // It is recommended to use the byte/word/long read rountines used on byte/word/long boundaries respectively. '' // '' // Returns true on success and false on failure. '' // '' // EEPROMaddress - Starting byte address of the data to access. '' // RAMaddress - Starting byte address of the data to write to. '' // ByteCount - Number of bytes to read. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// result := eepromPoll(EEPROMaddress) if(result) stopDataTransfer startDataTransfer result and= transmitPacket(constant((10 << 4) | 1) | ((EEPROMaddress >> 15) & $E)) repeat ((byteCount <# (65_536 - (RAMaddress #> 0))) #> 0) byte[RAMaddress++] := receivePacket(--byteCount) stopDataTransfer clearLock PUB writePage(EEPROMaddress, RAMaddress, byteCount) '' 14 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Writes bytes to the EEPROM. Uses a 19 bit addressing scheme which can access multiple EERPOMs on a bus. '' // '' // This rountine can only write to the page of the EEPROM selected. Any writes past that page will warp arround. '' // '' // It is recommended to use the byte/word/long write rountines used on byte/word/long boundaries respectively. '' // '' // Returns true on success and false on failure. '' // '' // EEPROMaddress - Starting byte address of the data to access. '' // RAMaddress - Starting byte address of the data to read from. '' // ByteCount - Number of bytes to write. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// result := eepromPoll(EEPROMaddress) if(result) repeat ((byteCount <# (65_536 - (RAMaddress #> 0))) #> 0) result and= transmitPacket(byte[RAMaddress++]) stopDataTransfer clearLock PUB ROMEngineStart(dataPinNumber, clockPinNumber, lockNumberToUse) '' 9 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Checks out a lock for the driver and changes the I2C Circuit pins. '' // '' // Returns true on success and false on failure. '' // '' // DataPinNumber - Pin to use to drive the SDA data line circuit. '' // ClockPinNumber - Pin to use to drive the SCL clock line circuit. '' // LockNumberToUse - Lock number to use if sharing the I2C bus (0 - 7). -1 to request a new lock number. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ROMEngineStop dataPin := ((dataPinNumber <# 31) #> 0) clockPin := ((clockPinNumber <# 31) #> 0) if((dataPin <> clockPin) and (chipver == 1)) lockNumber := lockNumberToUse if(lockNumberToUse == -1) lockNumber := locknew result or= ++lockNumber PUB ROMEngineStop '' 3 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Returns the lock used by the driver. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(lockNumber) lockret(-1 + lockNumber~) PRI eepromPoll(EEPROMaddress) ' 8 Stack Longs setLock startDataTransfer result := cnt repeat until(transmitPacket(constant(10 << 4) | ((EEPROMaddress >> 15) & $E))) stopDataTransfer startDataTransfer if((||(cnt - result)) > (clkfreq / constant(1_000 / 5))) return false result := transmitPacket(EEPROMaddress >> 8) result and= transmitPacket(EEPROMaddress) PRI transmitPacket(value) ' 4 Stack Longs value := ((!value) >< 8) repeat 8 dira[dataPin] := value dira[clockPin] := false dira[clockPin] := true value >>= 1 dira[dataPin] := false dira[clockPin] := false result := not(ina[dataPin]) dira[clockPin] := true dira[dataPin] := true PRI receivePacket(aknowledge) ' 4 Stack Longs dira[dataPin] := false repeat 8 result <<= 1 dira[clockPin] := false result |= ina[dataPin] dira[clockPin] := true dira[dataPin] := (not(not(aknowledge))) dira[clockPin] := false dira[clockPin] := true dira[dataPin] := true PRI startDataTransfer ' 3 Stack Longs outa[dataPin] := false outa[clockPin] := false dira[dataPin] := true dira[clockPin] := true PRI stopDataTransfer ' 3 Stack Longs dira[clockPin] := false dira[dataPin] := false PRI setLock ' 3 Stack Longs if(lockNumber) repeat while(lockset(lockNumber - 1)) PRI clearLock ' 3 Stack Longs if(lockNumber) lockclr(lockNumber - 1) DAT ' //////////////////////Variable Array///////////////////////////////////////////////////////////////////////////////////////// dataPin byte 29 ' Default data pin. clockPin byte 28 ' Default clock pin. lockNumber byte 00 ' Driver lock number. ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {{ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TERMS OF USE: MIT License /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }} \ No newline at end of file diff --git a/L298MotorPwm.spin b/L298MotorPwm.spin new file mode 100644 index 0000000..27a2f92 --- /dev/null +++ b/L298MotorPwm.spin @@ -0,0 +1,142 @@ +{{ + L298MotorsPwm.spin + Tom Doyle + 25 Feb 2007 + + Starts a cog to maintain a PWM signal to the L298 chip + The control pins on the L298 are controlled by the forward and reverse procedures + Speed is controlled by the update procedure + + In normal use it is not necessary to call any of these procedures directly as + they are called by the SetMotor.spin object +}} + +CON + + _clkmode = xtal1 + pll16x + _xinfreq = 5_000_000 + + +VAR + + long duty, period, pPin, dirM, I1pin, I2Pin ' par access + + byte cog + +PUB start(EnPin, In1Pin, In2Pin, pulsesPerCycle) : success + + ' EnPin - L298 Enable Pin + ' In1Pin - L298 Input 1 Pin + ' In2Pin - L298 Input 2 Pin + ' pulsesPerCycle - pulses per PWM cycle = clkfreq/pwmfreq + + pPin := EnPin + I1pin := In1Pin + I2pin := In2Pin + + duty := 0 + period := pulsesPerCycle + + reverse ' initialize dirM + success := cog := cognew(@entry, @duty) + + +PUB stop +{{ set esc PWM pin to off + stop cog }} + + waitpeq(0, |< pPin, 0) + dira[pPin] := 0 + if cog > 0 + cogstop(cog) + +PUB forward + + dirM := !0 + +Pub reverse + + dirM := 0 + + +PUB update(dutyPercent) + + duty := period * dutyPercent / 100 + + +DAT + +entry movi ctra,#%00100_000 + movd ctra,#0 + + mov addr, par + add addr, #8 ' L298 Enable (PWM) pin number + rdword _Enpin, addr ' stored in _EnPin + movs ctra,_Enpin + + mov temp, #1 + shl temp,_Enpin ' L298 Enable (PWM) pin + or dira, temp ' make an output + + mov addr, par + add addr, #16 ' L298 In1 pin + rdlong _In1Pin, addr ' stored in _In1Pin + mov temp, #1 + shl temp,_In1pin ' L298 In1 pin + or dira, temp ' make an output + + mov addr, par + add addr, #20 ' L298 In2 pin + rdlong _In2Pin, addr ' stored in _In2Pin + mov temp, #1 + shl temp,_In2pin ' L298 In2 pin + or dira, temp ' make an output + + + mov frqa,#1 + + mov addr, par + add addr, #4 ' pulses per pwm cycle + rdlong _cntadd, addr + mov cntacc,cnt + add cntacc,_cntadd + +:loop waitcnt cntacc,_cntadd + + mov tempDir, outa + + mov addr, par + add addr, #12 ' dirM + rdlong _dirM, addr ' store in _dirM + + mov tempDir, outa + + mov temp, #1 + shl temp,_In1Pin ' L298 In1 + test _dirM, 1 WZ ' check if direction = 1 + muxz tempDir, temp ' set Input 1 + + mov temp, #1 + shl temp,_In2Pin ' L298 In2 + test _dirM, 1 WZ ' check if direction = 1 + muxnz tempDir, temp ' set Input 2 + + mov outa, tempDir + + rdlong _duty,par + mov temp, par + add temp, #1 + rdlong _duty, temp + neg phsa,_duty + jmp #:loop + +_dirM res 1 ' motor direction 0 or 1 +_In1Pin res 1 ' L298 Input 1 Pin +_In2Pin res 1 ' L298 Input 2 Pin +tempDir res 1 ' temp direction +cntacc res 1 +_duty res 1 +_cntadd res 1 +_Enpin res 1 ' L298 Enable Pin +addr res 1 +temp res 1 \ No newline at end of file diff --git a/L298SetMotor.spin b/L298SetMotor.spin new file mode 100644 index 0000000..386441a --- /dev/null +++ b/L298SetMotor.spin @@ -0,0 +1,136 @@ +{{ + L298SetMotor.spin + Tom Doyle + 25 Feb 2007 + + Control of a DC motor with the L298 motor control chip. + The L298 chip does not use the traditional PWM, Direction and Brake control lines. + It uses what it refers to as the Enable line for PWM input and two lines refered to + as InX and InY for direction, coast and brake functions. The chip contains two controllers + and is readily available in a kit (L298 Compact Motor Driver) for less + than $20. The only deal better than this I have found is the Propeller Proto Board. + + The init procedure initializes local varibles and starts a PWM loop in a new cog + + The setMotor procedure sets the duty cycle (0%-100%), direction and delay per % change in + duty cycle. The delay per % change in duty cycle allows the motor speed to ramp up and down in + a smooth manner. The amount of delay to use will depend on the characteristics of the motor + and the load on the motor. This procedure is operating open loop which means that if the delay + per % change in duty cycle is not long enough you can over run the motor. The procedure keeps + track of the direction of the motor and will ramp the speed to 0 before changing direction. + The setMotor procedure is run in a new cog which waits for any previous operation to quit before + starting the new one. The setMotor cog is released after the new motor setting has been reached. + The pwm loop will run constantly in its own cog to keep the motor running at the set duty cycle. + +}} + +CON + + _clkmode = xtal1 + pll16x ' use crystal x 16 (5 x 16 = 80 Mhz) + _xinfreq = 5_000_000 + + _lcdPin = 0 ' Parallax 4x20 LCD Serial Line + + ' ESC Values + _escForward = 1 ' forward direction + _escReverse = 0 ' reverse direction + + +OBJ + + pwm[2] : "L298MotorPwm" ' Motor PWM object + + +VAR + + long Stack[50] + + WORD dutyCycleOld ' previous duty cycle value for ramp calculations + WORD directionOld ' previous directon value for reverse control + BYTE motorCog ' cog ID for setMotor + WORD escFreq ' ESC Frequency + BYTE pwmIndex ' pwm.spin index + + +PUB init(EnPin, In1, In2, Freq, pIndex) | pulsesPerCycle + +{{ + initialize electronic speed control + start pwm object in a new cog +}} + + escFreq := Freq + pwmIndex := pIndex + dutyCycleOld := 0 + directionOld := _escForward + pulsesPerCycle := clkfreq / escFreq + pwm[pwmIndex].start(EnPin, In1, In2, pulsesPerCycle ) + pwm[pwmIndex].reverse + motorCog := 0 + + +PUB setMotor(duty, Direction, delayPerStep) : success + + ' return value is cog 0-8 where 0 is no cog + + REPEAT + WHILE motorCog > 0 ' wait for end of previous operation + + success := (motorCog := cognew(csetMotor(duty, Direction, delayPerStep, @dutyCycleOld, @directionOld), @Stack) + 1) + + +PRI csetMotor(duty, Direction, delayPerStep, adrDCold, adrDirOld) | tempFreq, tempDuty, lDutyCycleOld, lDirectionOld + + + lDutyCycleOld := word[adrDCold] + lDirectionOld := word[adrDirOld] + + + IF (Direction <> lDirectionOld) AND (lDutyCycleOld > 0) ' stop motor before reversing + + REPEAT + + lDutyCycleOld := lDutyCycleOld - 1 + + tempFreq := escFreq + tempDuty := lDutyCycleOld + + pwm[pwmIndex].update(tempDuty) + + waitcnt(((CLKFREQ/1000) * delayPerStep) + cnt) + + WHILE lDutyCycleOld > 0 + + if Direction == _escForward + pwm[pwmIndex].forward + + if Direction == _escReverse + pwm[pwmIndex].reverse + + lDirectionOld := Direction + + REPEAT + tempFreq := 1000 + + IF lDutyCycleOld < duty + lDutyCycleOld := lDutyCycleOld + 1 + + IF lDutyCycleOld > duty + lDutyCycleOld := lDutyCycleOld - 1 + + tempDuty := lDutyCycleOld + + pwm[pwmIndex].update(tempDuty) + + waitcnt(((CLKFREQ/1000) * delayPerStep) + cnt) + + WHILE lDutyCycleOld <> duty + + lDutyCycleOld := duty + + word[adrDCold] := lDutyCycleOld + word[adrDirold] := lDirectionOld + + cogstop(motorCog~ - 1) ' stop cog and update cog variable + + \ No newline at end of file diff --git a/MCP3208.spin b/MCP3208.spin new file mode 100644 index 0000000..30e5004 Binary files /dev/null and b/MCP3208.spin differ diff --git a/NLAST4051.spin b/NLAST4051.spin new file mode 100644 index 0000000..b5551c9 Binary files /dev/null and b/NLAST4051.spin differ diff --git a/UAHLunarWormbotTest.spin b/UAHLunarWormbotTest.spin new file mode 100644 index 0000000..34bb1b0 --- /dev/null +++ b/UAHLunarWormbotTest.spin @@ -0,0 +1,92 @@ +{Object_Title_and_Purpose} + + +CON 'Global Constants + +'---Useful constants--- +HIGH = 1 +LOW = 0 +OUTPUT = 1 +INPUT = 0 +AVERAGE = 1 +CURRENT = 0 +FORWARD = 1 +REVERSE = 0 +INFINITY = 1 +ENABLE = 1 +DISABLE = 0 + +HIGH_SPEED_IO0 = 0 +HIGH_SPEED_IO1 = 1 +HIGH_SPEED_IO2 = 2 +HIGH_SPEED_IO3 = 3 +HIGH_SPEED_IO4 = 4 +HIGH_SPEED_IO5 = 5 + + +VAR 'Global variables + +long ExampleVariable + +OBJ 'Additional files you would like imported / included + +'Sol-X API that controls all the GDB hardware function +GDB : "GDB-API-V0.1.0" + +'Used to control clock timing functions +TIMING : "Clock" + +PUB Main 'First method called, like in JAVA + +'' Action: Initializes all the GDB hardware and firmware +'' Parameters: None +'' Results: Prepares the GDB for user interaction +''+Reads/Uses: None +'' +Writes: None +'' Local Vars: None +'' Calls: GDB.Initialize( ), GDB.SendText( ), TIMING.PauseSec( ) +'' GDB.GetNumber( ), and GDB.SetMotorShield( ) functions +'' URL: http://www.solarsystemexpress.com/store.html + +GDB.Initialize + +repeat 'Infinte Loop + + repeat + GDB.SendText(STRING("TYPE 1 and hit enter to extend L-16 actuators.")) + TIMING.PauseSec(5) 'Pause 5 seconds before outputing promote again + until(GDB.GetNumber) + + GDB.SetMotorShield(HIGH_SPEED_IO0, HIGH_SPEED_IO1, HIGH_SPEED_IO2, FORWARD) + GDB.SetMotorShield(HIGH_SPEED_IO3, HIGH_SPEED_IO4, HIGH_SPEED_IO5, FORWARD) + + repeat + GDB.SendText(STRING("TYPE 2 and hit enter to contract L-16 actuators.")) + TIMING.PauseSec(5) 'Pause 5 seconds before outputing promote again + until(GDB.GetNumber) + + GDB.SetMotorShield(HIGH_SPEED_IO0, HIGH_SPEED_IO1, HIGH_SPEED_IO2, REVERSE) + GDB.SetMotorShield(HIGH_SPEED_IO3, HIGH_SPEED_IO4, HIGH_SPEED_IO5, REVERSE) + +{{ See GDB-API-V.0.1 +PUB SetMotorShield(EnablePin, Input1Pin, Input2Pin, Direction) + + Action: More complex function to control actuator movement + Parameters: EnablePin - GDB GPIO pin connected to the "Enable Motor X Connector" on Seeed Studio Motor Driver + Input1Pin - GDB GPIO pin connected to the J7.1 (Channel A) or J7.5 (Channel B) on Seeed Studio Motor Driver + Input2Pin - GDB GPIO pin connected to the J7.4 (Channel A) or J7.6 (Channel B) on Seeed Studio Motor Driver + Direction - Sets direction of actuator movement using contsant FORWARD or REVERSE + Results: Changes the direction of current flow in the Seeed Studio Motor Driver ++Reads/Uses: None + +Writes: None + Local Vars: None + Calls: FullH_BridgeSubroutine( ) + URL: www.seeedstudio.com/wiki/Motor_Shield_V1.0 +}} + +PRI private_method_name + + +DAT +name byte "string_data",0 + \ No newline at end of file diff --git a/YourProject.spin b/YourProject.spin new file mode 100644 index 0000000..a7866ff --- /dev/null +++ b/YourProject.spin @@ -0,0 +1,64 @@ +{Object_Title_and_Purpose} + + +CON 'Global Constants + +'---Useful constants--- +HIGH = 1 +LOW = 0 +OUTPUT = 1 +INPUT = 0 +AVERAGE = 1 +CURRENT = 0 +FORWARD = 1 +REVERSE = 0 +INFINITY = 1 +ENABLE = 1 +DISABLE = 0 + +VAR 'Global variables + +long ExampleVariable + +OBJ 'Additional files you would like imported / included + +'Sol-X API that controls all the GDB hardware function +GDB : "GDB-API-V0.1.0" + +'Used to control clock timing functions +TIMING : "Clock" + +PUB Main 'First method called, like in JAVA + +'' Action: Initializes all the GDB hardware and firmware +'' Parameters: None +'' Results: Prepares the GDB for user interaction and test hardwares +''+Reads/Uses: None +'' +Writes: None +'' Local Vars: None +'' Calls: All the GDB API functions +'' URL: http://www.solarsystemexpress.com/store.html + +GDB.Initialize + +'REMOVE EVERYTHING BELOW HERE TO START WRITING YOUR OWN CODE. HAVE FUN :) + +GDB.UnitTest + +GDB.MeasureAnalogVoltage(0, GDB#AVERAGE, 50) +GDB.OutputAnalogVoltage(4095, 0) +GDB.TurnOffADC_DAC + +GDB.SetMotorDriver(GDB#FULL_H_BRIDGE_U1, GDB#FORWARD) +TIMING.PauseMSec(2000) 'PAUSE TWO SECONDS +GDB.SetMotorDriver(GDB#FULL_H_BRIDGE_U1, GDB#REVERSE) +GDB.SetHighPowerDriverDutyCycle(GDB#FULL_H_BRIDGE_U2, 75, GDB#FORWARD, 2000) + + + +PRI private_method_name + + +DAT +name byte "string_data",0 + \ No newline at end of file diff --git a/pasm_i2c_driver.spin b/pasm_i2c_driver.spin new file mode 100644 index 0000000..9727749 --- /dev/null +++ b/pasm_i2c_driver.spin @@ -0,0 +1,519 @@ +'' PASM I2C Driver Version 1.0 +'' Copyright (c) 2010 Dave Hein +'' June 6, 2010 +'' See end of file for terms of use + +'' This is a PASM version of Mike Green's Basic I2C Driver. The +'' low level I2C routines have been converted to PASM to increase the +'' I/O speed. These routines use the same calling interface as +'' the Basic I2C Driver Version 1.1 in the OBEX, and should be fully +'' compatible with any existing code that uses the Basic I2C Driver. + +'' Just like the Basic I2C Driver, the PASM I2C Driver assumes +'' that the SDA pin is one higher than the SCL pin. It assumes that +'' neither the SDA nor the SCL pins have pullups, so drives both. + +'' This object uses the Initialize method to start up a cog rather than using +'' the start method. This is done to remain consistent with the Basic I2C +'' Driver routines. Initialize must be called at the beginning of the program. +'' This loads the PASM code in a cog, and clocks the I2C bus to initialize +'' the devices on the bus. Subsequent calls may be made to Initialize, and +'' it will not cause the cog to be stopped or reloaded. + +'' The bus I/O speed is controlled by the constant DELAY_CYCLES. This constant +'' is used in the delay routine. The total delay consists of calling the delay +'' routine, performing a waitcnt of CNT + DELAY_CYCLES, and then returning +'' from the delay routine. Therefore, the total delay will be about +'' 12 + DELAY_CYCLES. + +'' The delay time represents the clock high time, and half the clock low time. +'' It is also used to determine the setup and hold times for the data bit for +'' read, write, start and stop operations. DELAY_CYCLES is defined with a +'' value of 52, which gives a total delay of 64 cycles. At 80 MHz, this is +'' 0.8 usecs, which is about one-third of a 400 KHz cycle time. This value +'' should be modified to provide the optimal speed for a particular application. + +'' Please see Mike Green's Basic I2C Driver object for more information on +'' the I2C routines, and on how EEPROMs are addressed + +CON + ACK = 0 ' I2C Acknowledge + NAK = 1 ' I2C No Acknowledge + Xmit = 0 ' I2C Direction Transmit + Recv = 1 ' I2C Direction Receive + + CMD_START = 1 ' Issue a start bit + CMD_STOP = 2 ' Issue a stop bit + CMD_READ = 3 ' Transmit a byte to the I2C bus + CMD_WRITE = 4 ' Read a byte from the I2C bus + CMD_INIT = 5 ' Initialize the I2C bus + CMD_READPAGE = 6 ' Read one or more bytes in the page mode + CMD_WRITEPAGE = 7 ' Write one or more bytes in the page mode + + DELAY_CYCLES = 52 ' I2C Delay time. Must be between 12 and 511 + +DAT + cognum long 0 + cmdbuf long 0, 0 + +PUB Initialize(SCL) +'' Start cog if not started, and initialize the devices on the I2C bus + 'ser.dbprintf1(string("i2c initialize %d\n"), SCL) + cmdbuf[1] := @SCL + cmdbuf := CMD_INIT + ifnot cognum + cognum := cognew(@cmdloop, @cmdbuf) + 1 + repeat while cmdbuf + +PUB Start(SCL) +'' Issue an I2C start command + cmdbuf[1] := @SCL + cmdbuf := CMD_START + repeat while cmdbuf + +PUB Stop(SCL) +'' Issue an I2C stop command + cmdbuf[1] := @SCL + cmdbuf := CMD_STOP + repeat while cmdbuf + +PUB Read(SCL, ackbit) +'' Read in i2c data, Data byte is output MSB first, SDA data line is +'' valid only while the SCL line is HIGH. SCL and SDA left in LOW state. + cmdbuf[1] := @SCL + cmdbuf := CMD_READ + repeat while cmdbuf + result := cmdbuf[1] + +PUB Write(SCL, data) +'' Write i2c data. Data byte is output MSB first, SDA data line is valid +'' only while the SCL line is HIGH. Data is always 8 bits (+ ACK/NAK). +'' SDA is assumed LOW and SCL and SDA are both left in the LOW state. + cmdbuf[1] := @SCL + cmdbuf := CMD_WRITE + repeat while cmdbuf + result := cmdbuf[1] + +PUB ReadPage(SCL, devSel, addrReg, dataPtr, count) : ackbit +'' Read in a block of i2c data. Device select code is devSel. Device starting +'' address is addrReg. Data address is at dataPtr. Number of bytes is count. +'' The device select code is modified using the upper 3 bits of the 19 bit addrReg. +'' Return zero if no errors or the acknowledge bits if an error occurred. + cmdbuf[1] := @SCL + cmdbuf := CMD_READPAGE + repeat while cmdbuf + ackbit := cmdbuf[1] + +PUB WritePage(SCL, devSel, addrReg, dataPtr, count) : ackbit +'' Write out a block of i2c data. Device select code is devSel. Device starting +'' address is addrReg. Data address is at dataPtr. Number of bytes is count. +'' The device select code is modified using the upper 3 bits of the 19 bit addrReg. +'' Most devices have a page size of at least 32 bytes, some as large as 256 bytes. +'' Return zero if no errors or the acknowledge bits if an error occurred. If +'' more than 31 bytes are transmitted, the sign bit is "sticky" and is the +'' logical "or" of the acknowledge bits of any bytes past the 31st. + cmdbuf[1] := @SCL + cmdbuf := CMD_WRITEPAGE + repeat while cmdbuf + ackbit := cmdbuf[1] + +PUB ReadByte(SCL, devSel, addrReg) : data +'' Read in a single byte of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. + if ReadPage(SCL, devSel, addrReg, @data, 1) + return -1 + +PUB ReadWord(SCL, devSel, addrReg) : data +'' Read in a single word of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. + if ReadPage(SCL, devSel, addrReg, @data, 2) + return -1 + +PUB ReadLong(SCL, devSel, addrReg) : data +'' Read in a single long of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. +'' Note that you can't distinguish between a return value of -1 and true error. + if ReadPage(SCL, devSel, addrReg, @data, 4) + return -1 + +PUB WriteByte(SCL, devSel, addrReg, data) +'' Write out a single byte of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. + if WritePage(SCL, devSel, addrReg, @data, 1) + return true + return false + +PUB WriteWord(SCL, devSel, addrReg, data) +'' Write out a single word of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. +'' Note that the word value may not span an EEPROM page boundary. + if WritePage(SCL, devSel, addrReg, @data, 2) + return true + return false + +PUB WriteLong(SCL, devSel, addrReg, data) +'' Write out a single long of i2c data. Device select code is devSel. Device +'' starting address is addrReg. The device select code is modified using the +'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred. +'' Note that the long word value may not span an EEPROM page boundary. + if WritePage(SCL, devSel, addrReg, @data, 4) + return true + return false + +PUB WriteWait(SCL, devSel, addrReg) : ackbit +'' Wait for a previous write to complete. Device select code is devSel. Device +'' starting address is addrReg. The device will not respond if it is busy. +'' The device select code is modified using the upper 3 bits of the 18 bit addrReg. +'' This returns zero if no error occurred or one if the device didn't respond. + devSel |= addrReg >> 15 & %1110 + Start(SCL) + ackbit := Write(SCL, devSel | Xmit) + Stop(SCL) + return ackbit + +DAT + +'*********************************** +'* Assembly language i2c driver * +'*********************************** + + org +' +' +' Entry +' Wait for a non-zero command and process +cmdloop rdlong t1, par wz + if_z jmp #cmdloop + mov parm1, par + add parm1, #4 + rdlong parm1, parm1 ' Get the address of the parameter list + + rdlong t2, parm1 ' SCL is always the first parameter + add parm1, #4 ' Point to the next parameter + mov scl_bit,#1 + shl scl_bit,t2 + mov sda_bit, scl_bit + shl sda_bit, #1 + + cmp t1, #CMD_READPAGE wz + if_z jmp #ReadPage1 + cmp t1, #CMD_WRITEPAGE wz + if_z jmp #WritePage1 + cmp t1, #CMD_READ wz + if_z jmp #read_byte + cmp t1, #CMD_WRITE wz + if_z jmp #write_byte + cmp t1, #CMD_START wz + if_z jmp #start1 + cmp t1, #CMD_STOP wz + if_z jmp #stop1 + cmp t1, #CMD_INIT wz + if_z jmp #initialize1 + neg parm1, #1 + +ReturnParm mov t1, par + add t1, #4 + wrlong parm1, t1 +signal_ready mov t1, #0 + wrbyte t1, par + jmp #cmdloop + +ReadPage1 call #ReadPageFunc + jmp #ReturnParm +WritePage1 call #WritePageFunc + jmp #ReturnParm +read_byte rdlong parm1, parm1 + call #readbytefunc + jmp #ReturnParm +write_byte rdlong parm1, parm1 + call #writebytefunc + jmp #ReturnParm +start1 call #StartFunc + jmp #ReturnParm +stop1 call #StopFunc + jmp #ReturnParm +initialize1 call #InitializeFunc + jmp #ReturnParm + +'' This routine reads a byte and sends the ACK bit. It assumes the clock +'' and data lines have been low for at least the minimum low clock time. +'' It exits with the clock and data low for the minimum low clock time. +readbytefunc mov ackbit1, parm1 ' Get the ACK bit + mov data1, #0 ' Initialize data byte to zero + andn dira, sda_bit ' Set SDA as input + call #delay + mov count1, #8 ' Set loop count for 8 + +:loop call #delay + or outa, scl_bit ' Set SCL HIGH + call #delay + shl data1, #1 ' data byte left one bit + test sda_bit, ina wz + if_nz or data1, #1 ' Set LSB if input bit is HIGH + andn outa, scl_bit ' Set SCL LOW + call #delay + djnz count1, #:loop + + cmp ackbit1, #0 wz + if_z andn outa, sda_bit ' Set SDA LOW if ACK + if_nz or outa, sda_bit ' Set SDA HIGH if NAK + or dira, sda_bit ' Set SDA as output + call #delay + or outa, scl_bit ' Set SCL HIGH + call #delay + andn outa, scl_bit ' Set SCL LOW + call #delay + mov parm1, data1 ' Return the data byte +readbytefunc_ret ret + +'' This routine writes a byte and reads the ACK bit. It assumes that the clock +'' and data are set as outputs, and the clock has been low for at least half the +'' minimum low clock time. It exits with the clock and data set as outputs, and +'' with the clock low for half the minimum low clock time. +writebytefunc mov data1, parm1 ' Get the data byte + mov count1, #8 ' Set loop count for 8 bits + +:loop shl data1, #1 ' Shift left one bit + test data1, #$100 wz ' Check MSB + if_z andn outa, sda_bit ' Set SDA LOW if zero + if_nz or outa, sda_bit ' Set SDA HIGH if not zero + call #delay + or outa, scl_bit ' Set SCL HIGH + call #delay + andn outa, scl_bit ' Set SCL LOW + call #delay + djnz count1, #:loop + + andn dira, sda_bit ' Set SDA as input + call #delay + or outa, scl_bit ' Set SDA HIGH + call #delay + test sda_bit, ina wz ' Check SDA input + if_z mov ackbit1, #0 ' Set to zero if LOW + if_nz mov ackbit1, #1 ' Set to one if HIGH + andn outa, scl_bit ' Set SCL LOW + call #delay + or dira, sda_bit ' Set SDA as output + mov parm1, ackbit1 ' Return the ack bit +writebytefunc_ret ret + +'' This routine transmits the stop sequence, which consists of the data line +'' going from low to high while the clock is high. It assumes that data and +'' clock are set as outputs, and the clock has been low for half the minimum +'' low clock time. It exits with the clock and data floating high for the +'' minimum high clock time. +stopfunc andn outa, sda_bit ' Set SDA LOW + call #delay + or outa, scl_bit ' Set SCL HIGH + call #delay + or outa, sda_bit ' Set SDA HIGH + call #delay + andn dira, scl_bit ' Float SCL HIGH + andn dira, sda_bit ' Float SDA HIGH +stopfunc_ret ret + +'' This routine transmits the start sequence, which consists of the data line +'' going from high to low while the clock is high. It assumes that the clock +'' and data were floating high for the minimum high clock time, and it exits +'' with the clock and data low for half the minimum low clock time. +startfunc or outa, sda_bit ' Set SDA HIGH + or dira, sda_bit ' Set SDA as output + call #delay + or outa, scl_bit ' Set SCL HIGH + or dira, scl_bit ' Set SCL as output + call #delay + andn outa, sda_bit ' Set SDA LOW + call #delay + andn outa, scl_bit ' Set SCL LOW + call #delay +startfunc_ret ret + +'' This routine puts the I2C bus in a known state. It issues up to nine clock +'' pulses waiting for the input to be in a high state. It exits with the clock +'' driven high and the data floating in the high state for the minimum high +'' clock time. +initializefunc andn dira, sda_bit ' Set SDA as input + or outa, scl_bit ' Set SCL HIGH + or dira, scl_bit ' Set SCL as output + call #delay + mov count1, #9 ' Set for up to 9 loops +:loop andn outa, scl_bit ' Set SCL LOW + call #delay + call #delay + or outa, scl_bit ' Set SCL HIGH + call #delay + test sda_bit, ina wz + if_nz jmp #initializefunc_ret ' Quit if input is HIGH + djnz count1, #:loop +initializefunc_ret ret ' Quit after nine clocks + +'' This routine delays for the minimum high clock time, or half the minimum +'' low clock time. This delay routine is also used for the setup and hold +'' times for the start and stop signals, as well as the output data changes. +delay mov delaycnt, cnt + add delaycnt, #DELAY_CYCLES + waitcnt delaycnt, #0 +delay_ret ret + +'PUB ReadPage(SCL, devSel, addrReg, dataPtr, count) : ackbit +readpagefunc rdlong devsel1, parm1 + add parm1, #4 + rdlong addrreg1, parm1 + add parm1, #4 + rdlong dataptr1, parm1 + add parm1, #4 + rdlong count2, parm1 + +'' Read in a block of i2c data. Device select code is devSel. Device starting +'' address is addrReg. Data address is at dataPtr. Number of bytes is count. +'' The device select code is modified using the upper 3 bits of the 19 bit addrReg. +'' Return zero if no errors or the acknowledge bits if an error occurred. +' devSel |= addrReg >> 15 & %1110 + mov t1, addrreg1 + shr t1, #15 + and t1, #%1110 + or devsel1, t1 +' Start(SCL) ' Select the device & send address + call #startfunc +' ackbit := Write(SCL, devSel | Xmit) + mov parm1, devsel1 + or parm1, #Xmit + call #writebytefunc + mov ackbit2, parm1 +' ackbit := (ackbit << 1) | Write(SCL, addrReg >> 8 & $FF) + mov parm1, addrreg1 + shr parm1, #8 + and parm1, #$ff + call #writebytefunc + shl ackbit2, #1 + or ackbit2, parm1 +' ackbit := (ackbit << 1) | Write(SCL, addrReg & $FF) + mov parm1, addrreg1 + and parm1, #$ff + call #writebytefunc + shl ackbit2, #1 + or ackbit2, parm1 +' Start(SCL) ' Reselect the device for reading + call #startfunc +' ackbit := (ackbit << 1) | Write(SCL, devSel | Recv) + mov parm1, devsel1 + or parm1, #Recv + call #writebytefunc + shl ackbit2, #1 + or ackbit2, parm1 +' repeat count - 1 +' byte[dataPtr++] := Read(SCL, ACK) +' byte[dataPtr++] := Read(SCL, NAK) +:loop cmp count2, #1 wz + if_z mov parm1, #NAK + if_nz mov parm1, #ACK + call #readbytefunc + wrbyte parm1, dataptr1 + add dataptr1, #1 + djnz count2, #:loop + +' Stop(SCL) + call #stopfunc +' return ackbit + mov parm1, ackbit2 +readpagefunc_ret ret + +'PUB WritePage(SCL, devSel, addrReg, dataPtr, count) : ackbit +writepagefunc rdlong devsel1, parm1 + add parm1, #4 + rdlong addrreg1, parm1 + add parm1, #4 + rdlong dataptr1, parm1 + add parm1, #4 + rdlong count2, parm1 + +'' Write out a block of i2c data. Device select code is devSel. Device starting +'' address is addrReg. Data address is at dataPtr. Number of bytes is count. +'' The device select code is modified using the upper 3 bits of the 19 bit addrReg. +'' Most devices have a page size of at least 32 bytes, some as large as 256 bytes. +'' Return zero if no errors or the acknowledge bits if an error occurred. If +'' more than 31 bytes are transmitted, the sign bit is "sticky" and is the +'' logical "or" of the acknowledge bits of any bytes past the 31st. +' devSel |= addrReg >> 15 & %1110 + mov t1, addrreg1 + shr t1, #15 + and t1, #%1110 + or devsel1, t1 +' Start(SCL) ' Select the device & send address + call #startfunc +' ackbit := Write(SCL, devSel | Xmit) + mov parm1, devsel1 + or parm1, #Xmit + call #writebytefunc + mov ackbit2, parm1 +' ackbit := (ackbit << 1) | Write(SCL, addrReg >> 8 & $FF) + mov parm1, addrreg1 + shr parm1, #8 + and parm1, #$ff + call #writebytefunc + shl ackbit2, #1 + or ackbit2, parm1 +' ackbit := (ackbit << 1) | Write(SCL, addrReg & $FF) + mov parm1, addrreg1 + and parm1, #$ff + call #writebytefunc + shl ackbit2, #1 + or ackbit2, parm1 +' repeat count ' Now send the data +' ackbit := ackbit << 1 | ackbit & $80000000 ' "Sticky" sign bit +' ackbit |= Write(SCL, byte[dataPtr++]) +:loop shl ackbit2, #1 wc + if_c or ackbit2, signbit + rdbyte parm1, dataptr1 + add dataptr1, #1 + call #writebytefunc + or ackbit2, parm1 + djnz count2, #:loop +' Stop(SCL) + call #stopfunc +' return ackbit + mov parm1, ackbit2 +writepagefunc_ret ret + +signbit long $80000000 +scl_bit res 1 +sda_bit res 1 +count1 res 1 +t1 res 1 +t2 res 1 +data1 res 1 +ackbit1 res 1 +delaycnt res 1 +parm1 res 1 +devsel1 res 1 +addrreg1 res 1 +dataptr1 res 1 +count2 res 1 +ackbit2 res 1 + +{{ + TERMS OF USE: MIT License + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +}} \ No newline at end of file