Jump to content


  • Content Count

  • Joined

  • Last visited

Posts posted by trossin

  1. Just got burned again on an 18F2620:

    If I use:

    rom const char table[]= { ....}; 

    it chews up RAM

    If I use:

    rom const char *table = {....}; it does not chew up RAM

    Using Version 7.22.  It is bad enough that I have to break my tables up into tiny 256 byte pieces but until I found this secret, I was ready to go to the dark side (Microchip compiler).

  2. I posted few new projects here (try Chrome if the pictures don't show up) :




    There are a couple videos of a Lynx Motion AL5D robot arm being driven by a single PIC which controls the servos and walks the spline by doing some math on the fly. The PC just sends the spline parameters and a step rate to get from the current position to the next position. The PIC has a little software FIFO so that the PC is a few positions (key frames) ahead. The PC and PIC handshake for FIFO space to allow playing long sequences. The second video and screen shot of the editor show a sequence with 33 keyframes to move a ball and USB drive around on a table.






  3. Most PIC processors do not have hardware divide logic so division is done in software. It is up to the compiler to decide to implement exception handling or not. Since code space is usually a premium, I would expect that BoostC does nothing but give you a bad answer. For most tiny embedded processors, you will have to check your inputs and handle divide by zero yourself so that you can handle it the way that is best for your application.

  4. My free website has been down for a good amount of time so I moved it here:




    I added a few new PIC projects (Wii Nunchuck interface using an 18F1330, TV speaker auto on/off and a stepper motor controller). I also have a servo control project I'm working on which uses spline interpolation of key frame values. I'm still working on the keyframe editor but it seems good enough for now. Here is a little video of it controlling a Lynxmotion robot arm:




    I'll post the schematic and code soon.

  5. SourceBoost runs fine on Windows 8 and Windows 8.1 and makes super code.


    MPLABX also runs fine on Windows 8.1 and the C compiler is free, supports floating point natively and variable args for printf. The catch is that it only is free for 18F processors and the code produced is not as small and fast as SourceBoost (for a large sum of money it will produce better code).


    The free Microchip compiler does not support the same function with different parameters like SB does nor does it have the lovely plugins and ability to write custom plugins for simulation. It is possible with some ifdefs to use common code that compiles on both tools.

  6. Why do the variables have to be together? The following code pieces can shift a 40 bit variable left or right by one bit and shift in the input Input. The 40 bit variable in Verilog speak is {High[31:0],Low[7:0]}.


    unsigned long High;

    unsigned char Low,Carry;

    unsigned char Input;


    // Shift Left

    Carry = (Low & 0x80) ? 1 : 0;

    High = (High<<1) | Carry;

    Low = (Low<<1) | Input;


    // Shift Right


    Carry = (High & 1) ? 0x80 : 0;

    High = (High>>1) | (Input ? 0x80000000 : 0);

    Low = (Low>>1) | Carry;

  7. Bug description:


    In the code below, the "ratio = (x==0) ? 0xffff : BigY/BigX;" returns the result of division the previous time this function was called when fixed_x is set to zero (which makes x 0). I attached a simple project which demonstrates the failure. I am able to work around this bug with an extra if statement "if(fixed_x==0) ratio = 0xffff;". Also, I still get the failure if I swap x for fixed_x in the original case.


    The code produced fails in the simulator as well as on Silicon (18F2620). It also fails with large and small memory models. In the simple example, the main function makes two calls to FixedAtan2 with different values but the second call gets the result of the first call which is -49.7 degrees instead of -90.0 degrees.


    int FixedAtan2(int fixed_y,int fixed_x) // Value returned is in 9.7 fixed point format.
        unsigned int x,y;
        unsigned int Above,Below,Frac;
        unsigned int ratio;
        int angle;
        unsigned char NegX,NegY;
        unsigned char TableIndex,Half;
        unsigned long BigY,BigX;
        if(fixed_x<0){ NegX=1; x = -fixed_x; }  else{ NegX=0; x = fixed_x; }
        if(fixed_y<0){ NegY=1; y = -fixed_y; }  else{ NegY=0; y = fixed_y; }
    	BigX = x;
    	BigY = (unsigned long)y<<8;
        ratio = (x==0) ? 0xffff : BigY/BigX;
    // Work around for complier bug    
        //if(fixed_x==0) ratio = 0xffff;
    Steps to reproduce:

    Build the attached projects and run to the while(1) in main. You will see AngleAboutX and AngleAboutY be the same values. If you single step into the second call, you can see the ratio equation produce the wrong answer.


    Expected behaviour:

    AngleAboutY should return 0xd300 which is -90.0 in 9.7 fixed point format.


    Is the problem 100% reproduceable:

    Yes. If fails every time.


    IDE version: 7.22

    Compiler: Compiler BoostC

    Compiler version: 7.22

    Target device: PIC18F2620

    OS: Windows 7 and Windows 8.1


  8. Is it possible to get sprint with variable arguments or support variable arguments in general like the following?


    void HeaderPrintf(char *Format, ...)


    va_list Marker;

    char Buffer[50];


    va_start(Marker,Format); /* Initialize variable arguments. */


    va_end(Marker); /* Reset variable arguments. */



  9. Below is assembly code that I use in my boot loader for 18F parts. The full project can be found here:




    Scroll down and click on Serial Port PIC Boot Programmer.


    I would think you could convert this to C code without much work but the problem is determining what are valid blocks to write.


    I hope this helps.


    ; ************************************************************************
    ; ** CmdEraseFlashRow: Get High address then low address and erase the	**
    ; **                   row of 64 bytes.  Bits 6:0 of the address are 	**
    ; **		       ignored.  0 is returned to signal the operation 	**
    ; **		       has finished.					**
    ; ************************************************************************		
    	clrf 	TBLPTRU 		; address of the memory block
    	call	GetRS232Byte 	; Fetch high address[15:8]
    	movwf 	TBLPTRH
    	call	GetRS232Byte 	; Fetch low address[7:6] [5:0] are ignored
    	movwf 	TBLPTRL
    	bsf 	EECON1, EEPGD ; point to Flash program memory
    	bcf 	EECON1, CFGS ; access Flash program memory
    	bsf 	EECON1, WREN ; enable write to memory
    	bsf 	EECON1, FREE ; enable Row Erase operation
    ;	bcf 	INTCON, GIE ; disable interrupts
    	movlw 	0x55
    	movwf	EECON2 ; write 55h
    	movlw 	0xaa
    	movwf 	EECON2 ; write 0AAh
    	bsf 	EECON1, WR ; start erase (CPU stall)
    ;	bsf 	INTCON, GIE ; re-enable interrupts
    	bra		CleanExit
    ; ************************************************************************
    ; ** CmdWriteFlashRow: Get High address then low address and 64 bytes   **
    ; **                   of data and write flash memory.  Bits 6:0 of the **
    ; ** 		       address are ignored. 0 is returned to signal the **
    ; **		       operation has finished.				**
    ; ************************************************************************	
    	clrf 	TBLPTRU ; address of the memory block
    	call	GetRS232Byte 	; Fetch high address[15:8]
    	movwf 	TBLPTRH
    	call	GetRS232Byte 	; Fetch low address some bit should not be set
    	movwf 	TBLPTRL
    		; Write data to internal flash buffer
    	movwf	Tmp
    	call	GetRS232Byte	; Get data to write
    	movwf 	TABLAT 			; present data to table latch
    	TBLWT*+ 				; write data, perform a short write
    							; to internal TBLWT holding register.	
    	decfsz	Tmp
    	bra		CmdWriteFlashRowLoop
    	TBLRD*-					; Point back to original row
    		; Write internal buffer to flash memory
    	bsf 	EECON1, EEPGD ; point to Flash program memory
    	bcf 	EECON1, CFGS ; access Flash program memory
    	bsf 	EECON1, WREN ; enable write to memory
    ;	bcf 	INTCON, GIE ; disable interrupts
    	movlw 	55h
    	movwf 	EECON2 ; write 55h
    	movlw 	0AAh
    	movwf 	EECON2 ; write 0AAh
    	bsf 	EECON1, WR ; start program (CPU stall)
    ;	bsf 	INTCON, GIE ; re-enable interrupts
    	bcf 	EECON1, WREN ; disable write to memory		
    	bra		CleanExi
    P.S. It only took 5 tries to get this to post correctly!!!

  10. OK. This one is a bit more intense than my CheapLA version because it uses a couple Xilinx CPLDs and external RAM but the PIC code shows examples of how to use the synchronous SPI interface to talk to the CPLDs and how to change the RS-232 baud rate on the fly when using faster serial cables. Code to control the timer output (to produce a 100Hz to 2.5 MHz clock) is also included.


    The project files and schematic can be found here:




    P.S. I also updated the cheap logic analyzer to work with 3.3V logic by turning off the on-die pull ups and using external pull downs to ground. There is a link to the cheap version at the location given above.

  11. I think you are not being nice to the compiler as it has no idea the dimensions of your array. It thinks you just passed a 1D array when you in fact passed a 2D array.


    Maybe try:


    void Init (unsigned char myMATRIX[][16]) {


    to let it know that it is a 2D array where the smallest index is 16. This way the compiler can calculate the offsets properly.


    If this does not work, maybe skip passing a pointer to MATRIX and just use the global variable inside your routine.


    I have a boot loader that I wrote in assembler that just fits in the last 0x180 bytes of flash starting at location 0xfe80. I would like to include this in some C code projects but I know the inline assembly messes with the code so I just want to toss a bunch of hex constants into the hex file for programming. I tried the technique below and was able to simulate correctly but when I look at the .hex file, there is no 01020304 string in the file.


    rom unsigned char BootCode[256] @ 0xf000 = {1,2,3,4};



    When I tried this technique, I did see entries in the hex file at 0xf010:


    unsigned char foo1() @ 0xf010





    Is there a secret to get the first version to work?


    Now that I think about it, I could just burn up a bit more space and just implement functions to erase, write and read a block of flash along with a little interpreter for the serial port and just shove it at the end of my code space using the foo1 function trick.


    What I would like is a way for my little application to be able to have its firmware updated without using bootmode pins or doing a multi-step program of the part. I have a nice clean way to do this for pure assembly programs but would like to do this as a single hunk of C.


    So, I guess never mind except it would be nice to figure out how to park some constants at a specific location.


    I also tried putting the following in the function instead of return(5):

    asm data 0x01,0x02,0x03,004


    And did get my bytes in flash memory. The only problem is that they are converted to 16 bit values and a line feed was added to the end:



    :0C says 12 bytes

    F010 says starting at address 0xf010

    00 says the type

    0100 is a 16 bit low byte first 1

    0200 is a 16 bit low byte first 2

    0300 is a 16 bit low byte first 3

    0400 is a 16 bit low byte first 4

    0500 is a 16 bit low byte first 5

    1200 is a 16 bit low byte first 0x12 (Line feed)

    D3 is the sumcheck value.


    Using 16-bit constants for asm data allows all the bytes to be written but with the order swapped and still gives the extra line feed.

    asm data 0x0123,0x4567,0x89ab




    I also tried "Hello" like the user manual says but the string is ignored.

    asm data "Hello" results in a syntax error. asm data 1,2,"Hello" drops the hello.

  13. I finished up adding write support as well as date and time to my SD project this Spring and finally got it on the web recently. With this code, it is possible to read, write and delete files as well as created and remove directories on FAT file systems built on MMC, SD or SDHC cards using long filenames.


    The project can be found here:




    This project uses the large memory model found in BoostC 7.xx. I should also mention that I developed this project with a custom SD card plugin that really helped ease development.


    I still need to add more detail to the web page but here is a list of the commands that can be used in local mode from a terminal:


    ls, cd, pwd, cat, new, rm, mkdir, rmdir, date, setdate, df, unmount, mount


    Here are the functions that the above commands are using:

    unsigned char FsMountFileSystem(unsigned char ReadOnly);

    void FsUnmountFileSystem(void);

    void FsPushCdStack(void);

    void FsPopCdStack(void);

    unsigned char FsGetFirstDir(char *Name,FsDirInfo *Info);

    unsigned char FsGetNextDir(char *Name,FsDirInfo *Info);

    unsigned char FsSeek(unsigned char FdIndex,unsigned long Offset,unsigned char Origin);

    unsigned char FsClose(unsigned char FdIndex);

    unsigned int FsRead(unsigned char FdIndex, unsigned int Count, unsigned char *Data);

    unsigned int FsWrite(unsigned char FdIndex, unsigned int Count, unsigned char *Data);

    unsigned char FsOpen(unsigned char Mode,char *Name);

    unsigned char FsRemove(char *Name);

    unsigned char FsMakeDir(char *Name);

    unsigned char FsRemoveDir(char *Name);

    void FsGetCurrentDirectory(char *Path);

    unsigned char FsSetCurrentDirectory(char *Name);

    unsigned long FsGetFreeSectors(void);

    void FsInit(void);



    Here are the commands that can be used in remote mode:

    #define FS_VERSION 1

    #define FS_INIT 2

    #define FS_READ_SECTOR 3

    #define FS_MOUNT 4

    #define FS_MOUNT_READ_ONLY 5


    #define FS_GET_FIRST_DIR 7

    #define FS_GET_NEXT_DIR 8

    #define FS_SET_CURRENT_DIR 9

    #define FS_GET_CURRENT_DIR 10

    #define FS_OPEN 11

    #define FS_READ 12

    #define FS_WRITE 13

    #define FS_CLOSE 14

    #define FS_SEEK 15

    #define FS_PUSH_DIR 16

    #define FS_POP_DIR 17

    #define FS_GET_FREE_SECTORS 18

    #define FS_REMOVE 19

    #define FS_MAKE_DIR 20

    #define FS_REMOVE_DIR 21

    #define FS_GET_TIME 22

    #define FS_SET_TIME 23

    #define FS_UNMOUNT 24

  14. I agree with Jorge that BoostC is the way to go. I also make my own libraries so I have just what I need. I tried C18 and found that it generated very bloated code compared to BoostC. Also, I needed to do a lot of typecasting and other ugly games to get it to use 8-bit variables correctly


    On a side note, I'm a big fan of the SourceBoost simulator and the ability to create custom plugins to emulate my external hardware (SD cards, NIXIE tubes, PWM motors, keypads and antique computers). This alone is worth the price of the tool and saves me a great deal of time and frustration developing projects


    I just do this for entertainment and not for profit but find that the pros at SourceBoost are very responsive to problems that I encounter.

  15. I downloaded version 7.20 and found that my original case still fails.


    I did more experiments on version 7.20 and found that the problem only shows up if your code is assembled at a somewhat large address. When label1 is 0x0028, the results are correct. If I moved it out to 0x1964 by adding more code it fails. In this case, the end of case 1 did a positive branch (nearly max) instead of a negative branch back to label 1. I attached a simpler project to reproduce the failure.


    I should also mention that this project has some code commented out that crashes the compiler with an access violation.


    Here are some snippets from the attached project .lst file showing the bug.


    1964 label1
    1964 520D MOVF main_1_command, F




    2164 6E04 MOVWF main_1_a+D'3'
    2166 D3FE BRA label1 // branch is signed number in bits 10:0 (this is a positive branch!).
    2168 label4
    2168 0E11 MOVLW 0x11
    216A 6E01 MOVWF main_1_a
    216C 6A02 CLRF main_1_a+D'1'
    216E 6A03 CLRF main_1_a+D'2'
    2170 6A04 CLRF main_1_a+D'3'
    2172 EFB2F00C GOTO label1
    2176 ; } main function end






  16. I tried a simpler case with just a large while loop and found that the compiler/assembler correctly generated a GOTO. So the bug seems to only be with case statements.


    void main()
    unsigned long a=0,b=1,c=2;

    a = a + b + c;
    a = a + b + c;


    a = a + b + c;
    a = a + b + c;



    10C0 5014 MOVF CompTempVar1002, W
    10C2 6E04 MOVWF main_1_a+D'3'
    10C4 EF12F000 GOTO label1
    10C8 ; } main function end

  17. If I want to look at a variable named BootSectorCommon.FirstRootDirSecNum in the watch bar, I am out of luck as it is more than 25 characters. I was forced to rename my structure BSC in order to debug my program.


    In a perfect world it would be super fantastic if the watch bar understood structures and would allow me to expand them to see the fields (like Visual C++).


    This is all low priority stuff but if it is easy, it would be nice to have for us long variable name people.


  18. Bug description:

    If the label for a branch (BRA) is too far away, no error is generated but instead the distance is truncated resulting in a branch to a bogus location.


    Steps to reproduce:

    See below in comments. I also attached the project


    Expected behaviour:

    The assembler should have produced an error or better yet, the compiler/linker should have generated a goto instruction since it has a much larger range.


    Is the problem 100% reproduceable:

    This happens every time with this code.


    IDE version: 7.11

    Compiler: BoostC

    Compiler version:

    "C:\Program Files\SourceBoost\boostc_pic18.exe" CBSDFileSystem.c -t PIC18F2620 -idx 2 -I ../CBLib -obj Debug -d _DEBUG

    BoostC Optimizing C Compiler Version 7.11 (for PIC18 architecture)

    Target device: PIC18F2620

    OS: Windows 7





    "C:\Program Files\SourceBoost\boostc_pic18.exe" CBSDFileSystem.c -t PIC18F2620 -idx 2 -I ../CBLib -obj Debug -d _DEBUG

    BoostC Optimizing C Compiler Version 7.11 (for PIC18 architecture)


    Building CASM file

    Memory Usage Report


    RAM available:3968 bytes, used:3647 bytes (92.0%), free:321 bytes (8.0%),

    Heap size:321 bytes, Heap max single alloc:127 bytes

    ROM available:65536 bytes, used:39368 bytes (60.1%), free:26168 bytes (39.9%)






    I'm working on a SD card FAT 12/16/32 file system and ran into a problem where the code running on the PIC and in the simulator misbehave. I tracked it down to what appears to be an assembler bug not flagging an error. Here is a little code segment from my giant case command interpreter case statement:



    ORG 0x00008E16

    8E16 RemoteMain_00000

    8E16 ; { RemoteMain ; function begin

    8E16 label744

    8E16 EC9CF03C CALL RS232getch_00000




    960E 5120 MOVF RemoteMain_00000_1_Resp, W, 1

    9610 010C MOVLB 0x0C

    9612 6F38 MOVWF RS232putch_00000_arg_ByteVal, 1

    9614 EC95F03C CALL RS232putch_00000


    9618 D3FE BRA label744


    This should have never assembled as the distance from the BRA label744 (address=0x9618) to the destination of label744 at 8E16 is -0x802 or negative 2050. The BRA instruction range is -1023 to +1023. The assembler/linker took the 2's complement of 0x802 and got 0x7fe, tossed bits 10 and 11 and came up with 0x3fe for the branch which is a positive branch instead of a negative branch so the program runs off the end of memory and wraps back to zero and restarts.


    Just build the attached project and look at the .lst file produced. I made this in debug mode which is what the project will default to when opened. I simulate with a couple custom plugins but you don't need to simulate to see the problem.




  19. #define SECTOR_FETCH16(Index) (*(unsigned short *)&SectorBuf[index])
    #define SECTOR_FETCH32(Index) (*(unsigned long *)&SectorBuf[index])
    #define BUF_FETCH32(Buffer) (*(unsigned long *)Buffer)
    //(SectorBuf[Offset+3]<<24) | (SectorBuf[Offset+2]<<16) | (SectorBuf[Offset+1]<<8) | SectorBuf[Offset+0])
    //(SectorBuf[Offset+1]<<8) | SectorBuf[Offset+0])


    I used the macros above as they resulted in less code on an 18F part than the shifting method in the comments. I would think that JorgeF's technique would result in less/faster code than the shifting. I also used the union technique in another situation so it would be worth doing the experiment to see which of the three tricks generate the best code.

  • Create New...