;this have to be called after setting ;maxvalue in config1. ;Have a look, that we have to scan up to 24 bits ;If we do this for 3 positions ( max,cur,target) ;in STEP_WORK we go up to over 800 cycles. ;so we have here to scan the maxvalue, and build ;a offset once a time after maxvalue is set. ;this offset, then is used by scan_direction ;Because this is not any time-sensitive stuff ;there is no calculation of cycles, and the ;code is more for good overviewing. ;after this: ;offsetbyte contains nr of byte containing the highest bit of maxval ;offsetbit contains nr to rol ;spec_flags.OFFSET_ROLLEFT is set, or not to show direction to rol init_scanoffset BCF spec_flags,OFFSET_ROLLEFT,AC MOVLW 0x03 MOVWF offsetbyte,AC MOVF maxpos3,W,AC BZ inioffb3empty BTFSC maxpos3,0x07,AC GOTO initscanoffbit7 BTFSC maxpos3,0x06,AC GOTO initscanoffbit6 BTFSC maxpos3,0x05,AC GOTO initscanoffbit5 BTFSC maxpos3,0x04,AC GOTO initscanoffbit4 BTFSC maxpos3,0x03,AC GOTO initscanoffbit3 BTFSC maxpos3,0x02,AC GOTO initscanoffbit2 BTFSC maxpos3,0x01,AC GOTO initscanoffbit1 BTFSC maxpos3,0x00,AC GOTO initscanoffbit0 inioffb3empty DECF offsetbyte,1,AC inioffb3 MOVF maxpos2,W,AC BZ inioffb2empty BTFSC maxpos2,0x07,AC GOTO initscanoffbit7 BTFSC maxpos2,0x06,AC GOTO initscanoffbit6 BTFSC maxpos2,0x05,AC GOTO initscanoffbit5 BTFSC maxpos2,0x04,AC GOTO initscanoffbit4 BTFSC maxpos2,0x03,AC GOTO initscanoffbit3 BTFSC maxpos2,0x02,AC GOTO initscanoffbit2 BTFSC maxpos2,0x01,AC GOTO initscanoffbit1 BTFSC maxpos2,0x00,AC GOTO initscanoffbit0 inioffb2empty DECF offsetbyte,1,AC inioffb2 MOVF maxpos1,W,AC BZ inioffb1empty BTFSC maxpos1,0x07,AC GOTO initscanoffbit7 BTFSC maxpos1,0x06,AC GOTO initscanoffbit6 BTFSC maxpos1,0x05,AC GOTO initscanoffbit5 BTFSC maxpos1,0x04,AC GOTO initscanoffbit4 BTFSC maxpos1,0x03,AC GOTO initscanoffbit3 BTFSC maxpos1,0x02,AC GOTO initscanoffbit2 BTFSC maxpos1,0x01,AC GOTO initscanoffbit1 BTFSC maxpos1,0x00,AC GOTO initscanoffbit0 inioffb1empty DECF offsetbyte,1,AC inioffb1 MOVF maxpos0,W,AC BZ initscanoffsetend ;this should never be happens, all is 0 BTFSC maxpos0,0x07,AC GOTO initscanoffbit7 BTFSC maxpos0,0x06,AC GOTO initscanoffbit6 BTFSC maxpos0,0x05,AC GOTO initscanoffbit5 BTFSC maxpos0,0x04,AC GOTO initscanoffbit4 GOTO initscanoffbx ;this is the case, if lownibble of byte 0 ;contains a poor number of max 16, ;or less, or nothing. ;--------------- ;now, we have to modify offsetbit, to a loopvalue ;which also shows the direction, where to rol to ;we need the highest 4 bits, for having 16 segments. ;offsetbyte contains number of byte, containing ;the highest bit. ;offsetbit has to set to nr to rol ;spec_flags.OFFSET_ROLLEFT is to set, when direction is left initscanoffbit0 ;rol this, and next byte ( if any ) 3 times to left MOVLW 0x03 MOVWF offsetbit,AC BSF spec_flags,OFFSET_ROLLEFT,AC GOTO initscanoffsetend initscanoffbit1 ;rol this, and next byte ( if any ) 2 times to left MOVLW 0x02 MOVWF offsetbit,AC BSF spec_flags,OFFSET_ROLLEFT,AC GOTO initscanoffsetend initscanoffbit2 ;rol this, and next byte ( if any ) 1 times to left MOVLW 0x01 MOVWF offsetbit,AC BSF spec_flags,OFFSET_ROLLEFT,AC GOTO initscanoffsetend initscanoffbit3 ;no work necessary, the lownibble contains all what we want MOVLW 0x00 MOVWF offsetbit,AC GOTO initscanoffsetend initscanoffbit4 ;rol this byte 1 times to right MOVLW 0x01 MOVWF offsetbit,AC GOTO initscanoffsetend initscanoffbit5 ;rol this byte 2 times to right MOVLW 0x02 MOVWF offsetbit,AC GOTO initscanoffsetend initscanoffbit6 ;rol this byte 3 times to right MOVLW 0x03 MOVWF offsetbit,AC GOTO initscanoffsetend initscanoffbit7 ;rol complete high-nibble to right, or use it directly MOVLW 0x04 MOVWF offsetbit,AC GOTO initscanoffsetend initscanoffbx MOVLW 0x00 MOVWF offsetbit,AC initscanoffsetend RETURN ;now, offsetbyte should contain the nr of first byte containing ;a valid value, and offsetbit the nr of the first bit which is 1 ;############# THE COMMAND WORK ####################### ;Note: All positons, set by s1,s2,s3,s4 or receives during ;r1,r2,r3,r4 depening on motors are handled as 1/32 fullstepvalues. ;Note: The frequency used to do motorstepping, and/or encoderscanning ;can be handled in two different ways: ;One is to set the flag INT_AS_FRQ. ;This means , every spi-int occures STEP_WORK will be called. ;Have a look for that you can send a sequence in two differnet ways, ;byte per byte, every effecting an interrupt, or all in one sequence, ;where the first byte received starts the interrupt. ;(Handling three boards, all using the same CS,and clock-line, ;ends in 21 bytes to handle, and 3 interrupts, if all send in one ;sequence. - Thats ends in a max. possible frequence of 7200 Hz ). ;The second way to handle frequencies is to use TIMER_AS_FRQ, and ;using a 16 bit timervalue. ;For all handable ways additionally a counter (steplp) is available, ;which is decremented every STEP_WORK. So with this you have additionally ;the possibility to split the frequency. ;All of this provide the feature, to set frequencies in a very sensible way. ;( A value of 0 for steplp means, no additionally splitting ). ;The encoderwork ignores steplp completely, means encoderscanning is every ;time done, STEP_WORK is called, if a step will be handled, or not. ; ;Note: The programloop of elmot-software only handles the testing for ;commands. If you use INT_HANDLES_CMD the programloop, has no effect. ; ; ;commandbyte ;this is handled by program-loop, using CMD_WORK ;or directly by interrupt, also using CMD_WORK ;(if INT_HANDLES_CMD is set ) ;first byte of sequence ( cmd-byte ) ;valid commands ( higher bits overrides lower bits ) ;7 6 5 4 3 2 1 0 ( bits 0,1,2 not used = address ) ;------------------------------------------------------ ;0 0 0 0 0 a a a NOP Useful for nothing, reducing performance, or getting current pos. ; s1,s2,s3,s4,s5,s6 not handled ; r1,r2,r3,r4 contains current position r5,r6 current encoderpos ; ; ; ;0 0 0 0 1 a a a set TARGET, normally the mostly used command. ; ; s1,s2,s3,s4 must contain new "target" positon, ; reflecting a 1/32 fullstepvalue. ; ; s5 depends on the settings on flags in s6 ; ; s6 This flag-bits steering additional the functionality ; ; s6.7 STEP_ON ;generally switch for calling STEP_WORK ; ;if this is not set, STEP_WORK ; ;only do its encoderwork, but nothing with the motors. ; ;This flag is also internally cleared, whenever ; ;current position is equal target position. ; ; ; s6.6 RESTART_FRQ ;This is also useful, for a stop after move, ; ;If this is 1, all counters, or timers, will ; ;be set to their starting conditions. ; ;Means, steplpcounter will be reset to steplp ; ;If TIMER_AS_FRQ is set timer will be restarted. ; ;After restarting the flag is internally cleared. ; ;This flag is also to use generally with the first command, ; ;if TIMER_AS_FRQ is used, to start it. ; ; s6.5 DONT_IGNORES5 ;Dont ignore content of s5 ; ;If this is 1, s5 will be used, depending on s6.4 ; ;If 0, s6.4, and s5 are ignored. ; ;This flag is also internally cleared, directly ; ;after setting content s5. ; ;(If your next sequence sets this flag again, ; ;also content will be set again ). ; ; s6.4 CONTENT_S5 ;content of s5, if s6.5 is set ; ;if this is 1 new steplp will be set from s5 ; ;(if INT_AS_FRQ, or additional to TIMER_AS_FRQ) ; ;if this is 0 the low-byte for the timervalue ; ;will be set from s5 ; ;(For case TIMER_AS_FRQ is used ) ; ; ; s6.3 reserved, currently not used ; ; s6.2 reserved, currently not used ; ; s6.1 reserved, currently not used ; ; s6.0 reserved, currently not used ; ; ; r1,r2,r3,r4 contains current position r5,r6 current encoderpos ; ;0 0 0 1 0 a a a set POSITION origin current positions ; s1,s2,s3,s4 must contain new "current" positon, s5,s6 new encoderpos ; there are no flags to set. ; r1,r2,r3,r4 contains current position r5,r6 current encoderpos ; ;x x 1 x x a a a stop directly, and receive positions. ; This cleares the STEP_ON flag, after receiving the first ; byte (commandbyte). So, - if INT_AS_FRQ is set, this first byte ; is the only one of the complete sequence, which can effect a step. ; After receiving the last byte, the targetposition is also ; set to the current position. ; With this you can stop stepping immediately, with returning ; the real current position. ; s1,s2,s3,s4,s5,s6 undefined, not effect ; r1,r2,r3,r4 contains current position r5,r6 current encoderpos ; ; ;------------------------------------------------------------ ;The configurations have to be done, before any of the stepping works is used. ;The normally way is after start-up, to send a config1, then a config2. ;After this the stepping can be switched on by using STEP_ON ;Have a look, that config1 uses a little bit more time ( up to 200 cycles ) ;as the others depending on a generally bitscanning of maxvalues. ; ; ;0 1 0 y y a a a GENERAL CONFIG ; s1 - s6 depends on y y y ( bit 4,3 ) ; r1 contains boards address, - r2,r3,r4,r5,r6 undefined. ; ;0 1 0 0 1 a a a config 1 ; s1,s2,s3,s4 have to contain 32bit value maxvalue ( maxcircle ) ; reflecting a 1/32 fullstep value. ; s5,s6 have to contain 16bit value encodervalue ( max nr. like 4000 ) ; ; currentpos will be tested after each step, if it is equal ; maxvalue. In this case currentpos is set to 0. ; If currentpos underflows 0, after going left, currentpos ; will be set automatically to maxvalue -1. ; ; The same will be doing with current encoderposition, and encodervalue. ; This provides in every case the possibility to handle ; the current position as a circle like 360 degrees. ; Be sure to handle also the setted targetposition in the right ; way. ; ; r1 contains boards address, - r2,r3,r4,r5,r6 undefined. ; ;0 1 0 1 0 a a a config 2 ; ; s1 have to contain highbyte for 16 bit timervalue. ; (If INT_AS_FRQ is used, this has no effect.) ; ; s2 have to contain lowbyte for 16 bit timervalue. ; ; s3 have to contain max. microstepvalue msmax ; (FS=32, HS=16, 1/4=8, 1/8=4, 1/16=2, 1/32=1) ; s4 have to contain min. microstepvalue msmin ; (FS=32, HS=16, 1/4=8, 1/8=4, 1/16=2, 1/32=1) ; ; Normally all steps are done with msmin,handling ; allways 1/32 fullstep * msmin, because all positions ; are handled in this size. If msmax a value wich is ; greater then msmin, internally an adapting of stepsize ; will be tried. This means if currentpos far away from ; targetpos mscur will tried to set to msmax, if next valid ; motorpositon this allowes. Also if current near target ; mscur will be tried to decrease to msmin. ; If this bother's you, set max to the same value as msmin. ; The default used value is allways msmin. ; ; s5 have to contain default value for steplp ; steplp can be used to adjust additionally the ; INT_AS_FRQ, or TIMER_AS_FRQ frequency. ; STEP_WORK funcs like this. If it is called, it ; first test for flag STEP_ON. If this is not set ; only encoder-work will be done. ; If set, it decrements a counter, if this overflows ; from 0 to 0xff, the step-work will be done, - if ; not overflow, STEP_WORK will only doing encodertest. ; A value of 0 means directly STEP_WORK. ; ; s6 sets the driver-flags, handling how the program/int works. ; ; s6.7 INT_AS_FRQ ;if 1, spi_int calls STEP_WORK, instead timer. ; ;if used spi-byte-per-int, ; ;spi-int funcs as frequency in this case. ; ;(for this, when using 3 driverboards, with the ; ;same cs-line, a max of 7200 Hz is recommended. ; ;in this 7200 Hz a complete sequence, plus ; ;CMD_WORK, and STEP_WORK can be handled for up ; ;3 boards using the same CS/CLOCK-line. ; ;If you send the sequence byte-per-byte ; ;you can use higher frequencies, but be carefull. ; ;You can also adjust this using steplp. ; ;This bit clears bits s6.6, and bit s6.2 ; ; s6.6 TIMER_AS_FRQ ;If this is 1, and s6.7 is 0, a timer will be used ; ;to call STEP_WORK, instead interrupt, in the way, ; ;that progloop compares a running timer with a configured ; ;timervalue. ; ;Have a look, that for target-systems a highly stable ; ;frequency is normally not necessary, - but anyway, ; ;we provide it :-) ; ;You can also divide this frq, using an additionally ; ;steplp for STEP_WORK. ; ;Have a look, that the spi-interrupt bother the ; ;stability of frequency. ; ; s6.5 INT_HANDLES_CMD ;if 1, spi_int handles CMD_WORK, instead progloop ; ; s6.4 reserved, currently not used ; ; s6.3 reserved, currently not used ; ; s6.2 NO_CIRCLE ;These flag shuts off, the handling of sections, instead ; ;calculation the direction dependend if currentpos is smaller ; ;then targetpos. Have a look, that over-/underflowhandling ; ;is done in the same way as for a circle. ; ;So if your motor is going along a flatline ; ;let him not move under 0, or over maxvalue. ; ; s6.1 reserved, currently not used ; ; s6.0 reserved, currently not used ; ; ATTENTION: These bits will be get as it is, so use it if ; you really know what you do. The effects of this are ; active directly next call of CMD_WORK. ; ; Have a look, that INT_AS_FRQ, and cmd-bit 7 = 1, together ; makes normally no sense, because interrupt then first call ; complete STEP_WORK, before receiving the rest of complete ; sequence. If it used anyway together, master have to wait ; after sending first byte ( cmd ), for at least the whole ; number of max. used cycles by STEP_WORK, before sending ; the rest of sequence. ; Another way, is to set INT_AS_FRQ off, with setTarget, ; before using sequence-per-int with cmd.7=1. ; ; r1 contains boards address, - r2,r3,r4,r5,r6 undefined. ; ;-------------------------------------------------------------------------------- ;1 x x x x a a a ALL THE SAME, but handled as complete sequence in one interrupt ; means, not received byte per interrupt, ; instead sequence received per single interrupt ;-------------------------------------------------------------------------------- ;ADDITIONAL NOTES: ;The Pin PORTC6 ( TXT ) is used as an digital output. ;Whenever current pos is equal to targetpos, this output is set to low ;Whenever current pos is not equal to target, this output is set to high ;You can use this for whatever digital inputs you want. ; ; CMD_WORK MOVLW 0x00 CPFSEQ spi_cmd,AC RETURN ;is 0, we do nothing ;spi_cmd contains a valid command BTFSC spi_cmd,H'0006',AC BRA cmdwork_config BTFSC spi_cmd,H'0005',AC BRA cmdwork_stopandclear BTFSC spi_cmd,H'0004',AC BRA cmdwork_setpos BTFSC spi_cmd,H'0003',AC BRA cmdwork_settarget BRA cmdworkend cmdwork_settarget MOVFF spiibuf0,target3 MOVFF spiibuf1,target2 MOVFF spiibuf2,target1 MOVFF spiibuf3,target0 MOVFF spiibuf5,run_flags BTFSS run_flags,DONT_IGNORES5,AC BRA cmdworkstend BCF run_flags,DONT_IGNORES5,AC BTFSS run_flags,CONTENTS5,AC BRA cmdstsettval MOVFF spiibuf4,steplp BRA cmdworkstend cmdstsettval MOVFF spiibuf4,timerlow cmdworkstend BTFSS run_flags,RESTART_FRQ,AC BRA cmdworkend MOVFF steplp,steplpctr BTFSS drv_flags,TIMER_AS_FRQ,AC BRA cmdworkend CALL start_timer BRA cmdworkend cmdwork_setpos MOVFF spiibuf0,curpos3 MOVFF spiibuf1,curpos2 MOVFF spiibuf2,curpos1 MOVFF spiibuf3,curpos0 MOVFF spiibuf4,encHigh MOVFF spiibuf4,encLow BRA cmdworkend cmdwork_stopandclear MOVFF curpos3,target3 MOVFF curpos2,target2 MOVFF curpos1,target1 MOVFF curpos0,target0 BRA cmdworkend cmdwork_config BTFSC spi_cmd,H'0005',AC BRA cmdwork_stopandclear BTFSC spi_cmd,H'0004',AC BRA cmdwork_config2 BTFSC spi_cmd,H'0003',AC BRA cmdwork_config1 BRA cmdworkend cmdwork_config1 MOVFF spiibuf0,maxpos3 MOVFF spiibuf1,maxpos2 MOVFF spiibuf2,maxpos1 MOVFF spiibuf3,maxpos0 MOVFF spiibuf4,encMaxHigh MOVFF spiibuf5,encMaxLow CALL init_scanoffset BRA cmdworkend cmdwork_config2 MOVFF spiibuf0,timerhigh MOVFF spiibuf1,timerlow MOVFF spiibuf2,msmax MOVFF spiibuf3,msmin MOVFF spiibuf3,mscur MOVFF spiibuf4,steplp MOVFF spiibuf5,drv_flags BTFSS drv_flags,H'0003',AC BRA cmdworkend ; skip if EEPROM_CFG is set ;here we are if EERPROM_CFG is set. ;@@@@@? should we implement this ? cmdworkend CLRF spi_cmd,AC ;at end we have to delete it RETURN ;( cycles with call, and return ) ;NOP max base 8 cycles max ;settarget max base 41 cycles max ;setpos max base 28 cycles max ;reserved max base 17 cycles ;config1 max base 30 cycles + ~ 100 init_scanoffset ;config2 max base 30 cycles max