Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

How to Add Support for ST Electronic uPSD33xx

2007-05-07
2013-03-12
  • Stephen Blair
    Stephen Blair
    2007-05-07

    My previous post entitled "ST Electronics uPSD Family of Processors" is really meant as a cry for help to add support for the uPSD3354 microprocessor.

    Should I create an mcs51reg_update.h file and submitt it?

    Thanks,
    Stephen Blair

     
    • ST also has a user forum. SDCC is mentioned there but corresponding include files have never found their way into SDCC:

      http://mcu.st.com/mcu/modules.php?mop=modload&name=Splatt_Forums&file=viewtopic&topic=377&forum=11

      (Nowadays an include file which uses the defines within compiler.h would be preferred. F.e. like here:
      http://sdcc.svn.sourceforge.net/viewvc/sdcc/trunk/sdcc/device/include/mcs51/ADuC84x.h?revision=4776&view=markup
      )

       
    • I just added uPSD33xx.h to the subversion repository:

      http://svn.sourceforge.net/viewvc/sdcc/trunk/sdcc/device/include/mcs51/uPSD33xx.h?view=log

      Please report any errors!

      J

       
      • > Please report any errors!

        Thanks a lot for adding:)

        And no error:) Just some strangeness between the
        initialization code for the uPSD posted here:
        http://sourceforge.net/forum/message.php?msg_id=4293380
        and table 16 of the datasheet
        "uPSD33xx (Turbo Series) Fast 8032 MCU with Programmable Logic"
        9685.pdf available here:
        http://www.st.com/stonline/products/literature/ds/9685.htm

        The IRQ with the highest priority at 0x63 within table 16
        is marked as "reserved" within the data sheet.
        YET the initialization code explicitely uses it and warns
        about its removal:

        ; Turbo Debug Interrupt Service routine - Do Not Remove
                CSEG AT 063H ; debug interrupt vector
                ...

        Seems some undocumented but nevertheless important
        feature is lurking there.

        Another topic: maybe add SFR16 definitions for the timers
        and the PCA unit (similar to those in C8051F520.h)
        for the uPSD as well?

        Greetings,
        Frieder

         
        • What about adding an ISR to the .h file?  Something like this:

          // Turbo Debug Interrupt Service routine - Do Not Remove
          void Turbo_Debug_interrupt(void) interrupt ((0x63-3)/8) _naked
          {
              _asm
              ANL 0xCF,#0xFD ; clear debug interrupt request flag
              nop
              _endasm;
          }

           
          • Maarten Brock
            Maarten Brock
            2007-05-10

            That violates the "no definitions in a header file" paradigm. If the file is included in two source files the linker will generate an error.

            If however you only insert the prototype and the header is included in the source containing main, the vector will be generated and the linker will require the ISR to be defined.

            I'm not up to speed with "inline" yet, but maybe that can solve this issue.

             
    • Maarten Brock
      Maarten Brock
      2007-05-08

      I noticed there is no P2 and no _XPAGE in the uPSD33xx.h. It seems the uPSD cannot use MOVX @Ri to access anything beyond the first 256 bytes. But it does have dual DPTR's. To make this work you need to adapt crtxclear.asm and crtxinit.asm in the libraries. If you want you can also adapt crtxstack.

      Maarten

       
    • wek
      wek
      2007-05-08

      I am not 100% certain for 33xx, but in 32xx I am sucessfully using MOVX @Ri to access all external code memory with P2 as a higher address.

      The documentation in this regard is unfortunately unclear, but in fact, although not connected to external pins, the P2 is present and connected internally to the PSD section as A8-A15.

      I would be very surprised if this would be otherwise in 33xx (and for that matter, 34xx, too). After all, these are normal '51s (with some enhancements), connected to the PSD (=FLASH+RAM+GAL in one chip) in a multichip module form.

      JW

      PS. I'd add at least the offsets to the PSD port registers to the .h, too.
      PS. OK, OK, I know. I should do it. Sorry, not today...

       
    • Maarten Brock
      Maarten Brock
      2007-05-08

      The datasheet says otherwise. 0xA0 is RESERVED. And it explicitly mentions it cannot access beyond the first 256 bytes (page 30).

      http://www.st.com/stonline/books/pdf/docs/9685.pdf

      I looked again and crtclear.asm doesn't need adaptation anymore than crtxstack does, assuming it's ok to write 0x00 to the reserved sfr at 0xA0.

      I'll upload a new version of crtxinit.asm later today that conditionally can use dual data pointers instead of movx @Ri. It will not be much smaller or faster either way as it will not use auto-toggle or auto-increment features. And it requires an sfr named DPS to be defined instead of DPTC/AUXR1 with bit 0 as the selector.

      Maarten

       
    • wek
      wek
      2007-05-08

      > The datasheet says otherwise. 0xA0 is RESERVED.
      > And it explicitly mentions it cannot access beyond the first 256 bytes (page 30).

      Well, then I AM very surprised. :-)

      In the afternoon when I wrote that I checked with my uPSD33xx datasheet and P2 WAS there, and  - now I looked better and that is a preliminary datasheet from 2003, I never needed a newer one...

      I think the difference is beceause of the memory manager built into the 33xx/34xx (prefetch & jump cache).

      I still think the .h can be augmented with definitions for the PSD register offsets... Or, even better, declare the registers as variables in XDATA memory, based on a base address for the registers to be passed to the .h - something like:

      #ifndef PSD_CSIOP
      #define PSD_CSIOP 0x1000   // some arbitrary default value
      #endif

      xdata at PSD_CSIOP+0xE2 unsigned char PSD_VM;
      etc.

      and the usage would be

      someprogram.c:

      #define PSD_CSIOP 0x3000
      #include <upsd3xx.h>

      Is this a good idea?

      JW

       
      • Maarten Brock
        Maarten Brock
        2007-05-09

        Instead of the explicit

        xdata at PSD_CSIOP+0xE2 unsigned char PSD_VM;

        please use the macro SFRX from compiler.h. That's what it's for.

        I assume these registers can be mapped to a variable base address then. Do they actually have a default base or are you required to always set it?  If there is no default I would tend to leave out the default value from the header file along with all SFRX definitions. This forces the user to think about what he/she's doing and supply the base. It will generate an error otherwise, unless these xdata registers are not used at all.

        Now who volunteers?

         
    • wek
      wek
      2007-05-09

      Think of it as the registers are chip-selected from a GAL(PLD)-based address decoder, so the base address is determined by having configured (created a "bitstream") for the the GAL(PLD).

      So, at the end of the day, the base address is user defined and, yes, (s)he should enter it explicitly. It is very unlikely that somebody would use a uPSD and NOT use any of these registers - at least they are needed to write and read to/from pins other than P1/P3 (i.e. roughly half of the I/O of the chip)...

      Is there any standard mechanism to throw an explicit error, possibly explaining the cause of the error to the unaware user? Something like:

      #ifndef PLD_CSIOP
      #throw_error You should define PLD_CSIOP according to the chip configuration
      #endif

      ?

      JW

      PS. I am working on the register definitions...

       
    • wek
      wek
      2007-05-09

      OK I've discovered the #error directive :-)

      Please don't laugh too loudly. I still AM a C-hater.

      JW

       
    • wek
      wek
      2007-05-09

      Submitted as patch #1715750 (although it is not a patch :-| )

      Next step: uPSD32xx.h and uPSD34xx.h . They should be pretty similar. I am rather tired at the moment...

      JW

       
      • Added.

         
    • Stephen Blair
      Stephen Blair
      2007-05-13

      Thank you all very much for all the help, information, and especially the uPSD33xx.h file.  I've been very busy and just now got back to SDCC and was amazed.

      Best Regards,
      Stephen Blair

       
    • Stephen Blair
      Stephen Blair
      2007-05-14

      I'm trying to start out with the Blink_LED code included with Keil compiler.  Their sample code works on my target processor and the LEDs blink correctly.  Now I'm tring to get it to work with SDCC and am having trouble with the below noted areas:

      #define PSD_CSIOP    0x7F00
      #include <uPSD33XX.h>
      #include "upsd3300_timer.h"

      #define LED1_ON_LED2_ON        0xF9
      #define LED1_OFF_LED2_OFF    0xFF
      #define LED1_ON_LED2_OFF    0xFB
      #define LED1_OFF_LED2_ON    0xFD

      #define LONG    100
      #define MEDDIUM     50
      #define SHORT     10

      #define YES    1
      #define NO  0

      //xdata volatile PSD_REGS PSD_reg _at_ PSD_CSIOP; // Cannot find reference to PSD_REGS in Keil, so needless to say there isn't on in SDCC

      void main(void)
      {
          static char blink_delay, blink_leds_together;

          blink_delay = LONG;
          blink_leds_together = NO;

          timer0_init();

      //    PSD_PSD_reg.PMMR0|=0x08;    // Use PSD.reg or...
          PSD_CSIOP.PMMR2|=0x3C;        // PSD_CSIOP ?  Neither works.

          PSD_CSIOP.DIRECTION_D|=0x06;
          PSD_CSIOP.DATAOUT_D = LED1_OFF_LED2_OFF;

          While (1)
          {
              if(blink_leds_together == YES)
                  PSD_CSIOP.DATAOUT_D = LED1_ON_LED2_ON;
              else
                  PSD_CSIOP.DATAOUT_D = LED1_ON_LED2_OFF;

              timer0_delay(blink_delay);

              if(blink_leds_together == YES)
                  PSD_CSIOP.DATAOUT_D = LED1_OFF_LED2_OFF;
              else
                  PSD_CSIOP.DATAOUT_D = LED1_OFF_LED2_ON;

              timer0_delay(blink_delay);
          }
      }

      Any Help would be greatly appreciated.

      Best Regards,
      Stephen Blair

       
      • Please check the file "uPSD33XX.h" for the register names.  For example, instead of using:

        PSD_CSIOP.PMMR0|=0x08;
        PSD_CSIOP.PMMR2|=0x3C;

        PSD_CSIOP.DIRECTION_D|=0x06;
        PSD_CSIOP.DATAOUT_D = LED1_OFF_LED2_OFF;

        you should use:

        PSD_PMMR0|=0x08;
        PSD_PMMR2|=0x3C;

        PSD_DIRECTION_D|=0x06;
        PSD_DATAOUT_D = LED1_OFF_LED2_OFF;

        and such.

           

         
    • Stephen Blair
      Stephen Blair
      2007-05-15

      That did it.  It's always the simple things at first.

      Now I cannot get the ISR for TIMER0 to fire:
      //-------------------------------------------------------------------------
      // Blink_LED.c
      //
      #define PSD_CSIOP    0x7F00
      #include <uPSD33XX.h>
      #include "upsd3300_timer.h"

      #define LED1_ON_LED2_ON        0xF9
      #define LED1_OFF_LED2_OFF    0xFF
      #define LED1_ON_LED2_OFF    0xFB
      #define LED1_OFF_LED2_ON    0xFD

      #define LONG    100
      #define MEDDIUM     50
      #define SHORT     10

      #define YES    1
      #define NO  0

      main()
      {
          static char blink_delay, blink_leds_together, use_timer0;
          static long x, y;

          blink_delay = LONG;
          blink_leds_together = NO;
          use_timer0 = YES;

          if(use_timer0 == YES)
              timer0_init();

          PSD_PMMR0|=0x08;
          PSD_PMMR2|=0x3C;

          PSD_DIRECTION_D|=0x06;
          PSD_DATAOUT_D = LED1_OFF_LED2_OFF;

          while (1)
          {
              if(blink_leds_together == YES)
                  PSD_DATAOUT_D = LED1_ON_LED2_ON;
              else
                  PSD_DATAOUT_D = LED1_ON_LED2_OFF;

              if(use_timer0 == YES)
                  timer0_delay(blink_delay);
              else
              {
                  y=0;
                  for(x=0; x<10000L; x=x+1)
                  {
                      y=y+1;
                  }
              }

              if(blink_leds_together == YES)
                  PSD_DATAOUT_D = LED1_OFF_LED2_OFF;
              else
                  PSD_DATAOUT_D = LED1_OFF_LED2_ON;

              if(use_timer0 == YES)
                  timer0_delay(blink_delay);
              else
              {
                  y=0;
                  for(x=0; x<10000L; x=x+1)
                  {
                      y=y+1;
                  }
              }
          }
      }
      //-------------------------------------------------------------------------

      //-------------------------------------------------------------------------
      // upsd3300_timer.c
      //
      #define PSD_CSIOP    0x7F00
      #include "upsd33XX.h"
      #include "upsd3300_timer.h"

      /*------------------------------------------------------------------------------
                    Global Variable Declarations
      ------------------------------------------------------------------------------*/
      static unsigned int idata timer0_tick;
      static unsigned int idata timer0_value;

      #define FREQ_OSC    40000
      /*------------------------------------------------------------------------------
      timer0_isr()

      This function is an interrupt service routine for TIMER 0.  It should never
      be called by a C or assembly function.  It will be executed automatically
      when TIMER 0 overflows.

      This ISR stops timer0, adjusts the counter so that another interrupt occurs in
      10ms, and then restarts the timer.
      ------------------------------------------------------------------------------*/
      static void timer0_isr (void) interrupt TIMER0_INTERRUPT using 1
      {
          TR0 = 0;                      /* stop timer 0 */
          TL0 = (timer0_value & 0x00FF);
          TH0 = (timer0_value >> 8);
          TR0 = 1;                      /* start timer 0 */
          timer0_tick++;                // Increment global var timer_tick (number of 10ms ticks)
      }

      /*------------------------------------------------------------------------------
      timer0_init();

      This function enables TIMER 0.  TIMER 0 will generate a synchronous interrupt
      once every 100Hz (10ms).
      ------------------------------------------------------------------------------*/
      void timer0_init (void)
      {
          EA = 0;                 /* disable interrupts */
          timer0_tick = 0;
          TR0 = 0;                /* stop timer 0 */
          TMOD &= 0xF0;           /* clear timer 0 mode bits - bottom 4 bits */
          TMOD |= 0x01;           /* put timer 0 into 16-bit no prescale */

          // Calculate timer rollover based on FREQ_OSC to be 10ms periods (100hz)
          timer0_value = 0x10000 - ( ((FREQ_OSC * 5L) / 6L) - 17L);
          TL0 = (timer0_value & 0x00FF);
          TH0 = (timer0_value >> 8);

          PT0 = 1;                /* set high priority interrupt for timer 0 */
          ET0 = 1;                /* enable timer 0 interrupt */
          TR0 = 1;                /* start timer 0 */
          EA = 1;                 /* enable interrupts */
      }

      /*------------------------------------------------------------------------------
      timer0_count ();

      This function returns the current Timer 0 tick count.
      ------------------------------------------------------------------------------*/
      unsigned int timer0_count (void)
      {
          unsigned int t;

          EA = 0;               // disable interrupts to read a non-changing value
          t = timer0_tick;
          EA = 1;               // enable interrupts
          return(t);
      }

      /*------------------------------------------------------------------------------
      timer0_delay (count);

      This is a delay function that waits for the specified number of timer 0 ticks to
      pass before returning.

      count   - unsigned int
              - the number of timer ticks to wait before returning from function.
      ------------------------------------------------------------------------------*/
      void timer0_delay (unsigned int count)
      {
          unsigned int start_count;

          start_count = timer0_count(); /* get the start count */

          while ((timer0_count() - start_count) <= count)   /* wait for count "ticks" */
          {
              PCON |= 0x01;    // Idle MCU to wait for timer tick
          }
      }
      //-------------------------------------------------------------------------

      I hate to ask for so much assistance but I've got to get over this learning curve.

      Best Regards,
      Stephen Blair

       
      • Maarten Brock
        Maarten Brock
        2007-05-15

        Stephen,

        This is one of the quirks of SDCC. It needs to see at least the prototype of the ISR's in the file containing main() so it can fill the interrunpt vector tabel. I guess you'll have to remove the static keyword from it too. It's all in the manual.

        Maarten