Small test code that does not work

Help
2014-04-25
2014-04-27
  • Raphael Neider
    Raphael Neider
    2014-04-26

    Hi,

    it would help to state

    1. what exactly does not work (compilation errors? runtime misbehaviour?),
    2. what has been expected to happen,
    3. and what has been observed instead.

    I have added double quotes around pic16f628.h (these might have been lost in the forum), fixed the address of the config word to 0x2007 (or _CONFIG), and fixed the name of the DATA_CP_OFF config option (which for unknown reasons has no leading underscore character).
    I have also fixed the sdcc-specific keywords __code, __at and __interrupt to use their standards compliant, double-underscore prefixed form. I also put the arguments to sdcc-specific keywords into parens to allow replacing them with compiler-specific keywords for other compilers or even remove them completely via preprocessor magic.

    Apart from cosmetic changes (whitespace around operators, including =), I think I did not make more changes.

    The below code compiles and assembles for me with the current SDCC subversion head revision r9010, version 3.4.1.
    Command used to compile:
    /media/data/local/sdcc-20140426/bin/sdcc -mpic14 -p16f628a --use-non-free led-on.c

    I cannot test whether the code actually works as expected on the target devices. You may need to play around with ADCON to make port A pins digital outputs (rather than having them configured to analog inputs), but I would have to check the data sheet for details.

    Oh, and by the way: Putting a line with 4 tilde characters before and after your code allows for proper markup and keeps indentation/special characters intact:

    ~~~~
    /* your code here */
    ~~~~

    #include "pic16f628a.h"
    #include "stdio.h"
    
    /* _CONFIG = 0x2007 */
    __code int __at(_CONFIG) __CONFIG = _CP_OFF & DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSC_OSC_NOCLKOUT;
    
    void isr() __interrupt(0)
    {
      /* interrupt service routine */
      /* << insert interrupt code >> */
    }
    
    void Setup()
    {
      TRISA = 0b000000;
      TRISB = 0b00000000;
      PORTA = 0b000000;
      PORTB = 0b00000000;
      PCON = 0b00001000;
      INTCON = 0b00000000;
      CMCON = 0b00000111;
      CCP1CON = 0b00000000;
    }
    
    void main(void)
    {
      Setup();
      while (1)
        {
          RA1 = 1;
        }
    }
    
     
    Last edit: Raphael Neider 2014-04-26
  • alejandro1957
    alejandro1957
    2014-04-26

    what exactly does not work (compilation errors? runtime misbehaviour?).
    compiles fine, no errors
    what has been expected to happen
    as seen in the main only has to turn on an LED on PORTA.1
    and what has been observed instead.
    does not light up anything.
    simple circuit:
    pin 14 to Vdd
    pin 5 to Vss
    PORTA.1 to resistance 220 + led to GND
    I will modify the value to config 0x2007,even though i set the bits as datasheet says to 0x2104(10000100000100).
    yes, the actual code is different to what you see.
    manifest error of shaping the post.
    I program in basic for pic (GCBasic),but i would like to begin to learn in C (using linux for 10 years)
    thank you and let you know

     
  • Raphael Neider
    Raphael Neider
    2014-04-26

    You want

    __code int __at(0x2007) cfg0 = 0x2104;

    __code int __at(0x2007) declares an integer (16-bit) entity in code memory (ROM or EEPROM, not RAM) at address 0x2007 (which is the (virtual) address assigned to the config word for your device).
    Implementation detail: The actual data type is ignored for config words, but it's generally a good idea to use a proper type (i.e., uint16_t, int16_t, unsigned int or int). Types such as uint8_t or char would probably work as well for the config word, but initializing them with a > 8 bit initializer value would at least look strange and might fail in the future.

    cfg0 would be the C symbol to access this entity at runtime, but since config words are handled specially, this symbol must not be used except during its definition. If I remember correctly, the symbol is not really defined or accessible from C; the linker should never see it. It is just there to satisfy C syntax rules ;-)
    I recommend against using a reserved name (starting with an underscore) as these might collide with compiler-generated (or library-internal) symbols.

    = 0x2104 initializes the 16-bit entity at the config word location to the bit pattern 0b0010.0001.0000.0100 as you requested. The previous definition used preprocessor #defines from pic16f628a.h to symbolically compute the (initial) value at compile time.
    I am not sure if
    _CP_OFF & DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSC_OSC_NOCLKOUT == 0x2104.

    The safe bet is to look up the bit pattern via the data sheet and use
    __code int __at(0x2007) cfg0 = 0x2104;
    with the hardcoded address 0x2007 (from the device data sheet) after __at and the (hex-encoded) numeric value after the equals sign -- just as you planned.

    I would be glad to hear about success/failure.

    Raphael

     
  • alejandro1957
    alejandro1957
    2014-04-27

    forget it.
    I realized that the program is reset at the end of each cycle(main)and startover.
    I enabled MLCRE and put a 10K resistor pull-up.
    but nothing,continues to reset and start over.
    the same with a code on the pwm.
    the pic has a 16F628A with internal oscillator to 4mhz.
    the IDE is Code :: Blocks IDE for SDCC

     
  • Raphael Neider
    Raphael Neider
    2014-04-27

    When you allow main to return, the PIC will experience a call-stack underflow and reset.

    Rationale:
    In the RESET vector (where program execution starts after power up or reset), we have

    PAGESEL __sdcc_gsinit_startup
    GOTO    __sdcc_gsinit_startup
    

    In __sdcc_gsinit_startup, we finally have

    GOTO _main
    

    which takes execution to the first instruction in the user-defined main().

    Note that the PIC's internal call stack is still empty when entering main.

    The last instruction in main (as in each function) is

    RETURN
    

    which would try to fetch the return address from the call stack -- which is empty at this point ==> reset.

    If you want to halt the PIC upon reaching the end of main, you should use something like

    void main(void)
    {
      /* your main code here */
    
      while (1) {
        /* halt system */
      }
    }
    
     
  • alejandro1957
    alejandro1957
    2014-04-27

    thanks for the information.
    practically when it comes out of the code,goes into idle loop.
    inelegant,but functional.
    will try it.

     
  • alejandro1957
    alejandro1957
    2014-04-27

    great, now works well
    Delay_ms & Delay_us --> OK
    Blink ----------------> OK
    PWM ------------------> OK
    Internal Eeprom ------> OK
    USART ----------------> OK

     
    Last edit: alejandro1957 2014-04-27