Freescale S08 - how to get a string of ASCII characters into the data buffer

Thread Starter

mgookin

Joined Mar 21, 2017
11
Dear Group:

We are working on a project where our lead EE passed away over the holidays. He had written the machine language for our MCU Freescale MC9S08QG8CFFE (data sheet: http://www.nxp.com/assets/documents/data/en/data-sheets/MC9S08QG8.pdf ). One objective is to receive a string of ASCII characters from another chip (that chip is named J3 in our code) and put the characters in the data buffer. This is where we are stuck. We can not seem to get the ASCII characters into the data buffer.

His work all seems logical. His work is in machine language and we are putting it in C in Code Warrior. If we can get the characters to load into the data buffer, we can take it from there.

Here's his work:

Code:
; Include derivative-specific definitions and export symbols

            INCLUDE 'derivative.inc'
            XDEF _Startup
            ABSENTRY _Startup

; variable/data section

            org    Z_RAMStart      

MS_100_Cnt    ds.b       1
Sec_Cnt        ds.b    1
Min_Cnt        ds.b    1
Hour_Cnt    ds.b    1

Dly_Cnt     ds.b       1                    ;delay routine counter


            org    ROMStart                ;start of code space
_Startup:
            ldhx   #RAMEnd+1           ; initialize the stack pointer
            txs

; configure System Options Register

            lda #%01000010             ;b7 COP disabled, long timeout, PTA4 is output
;                 ||||||||
;                 |||||||+------------- RESET Pin Enable
;                 ||||||+-------------- Background Debug Mode Pin Enable
;                 |||||+--------------- not used
;                 ||||+---------------- not used
;                 |||+----------------- not used
;                 ||+------------------ Stop Mode Enable (not)
;                 |+------------------- COP Watchdog Timeout Period (1= long)
;                 +--------------------    COP Watchdog Enable Disabled
            sta     SOPT1

; these are the port configurations for the demo board, they should remain the same for the J3 prototype board

; configure port A and B data registers

            mov    #%00010000,PTAD                ;b4-7 not pinned out, clear unused pins low
;                 ||||||||
;                 |||||||+------------- PTA0 not used
;                 ||||||+-------------- PTA1 not used
;                 |||||+--------------- PTA2 not used
;                 ||||+---------------- PTA3 not used
;                 |||+----------------- PTA4 used by flash programmer, input only
;                 ||+------------------ PTA5 used by flash programmer, output only
;                 |+------------------- not pinned out
;                 +--------------------    not pinned out

            mov    #%00001011,PTBD                ;only lower nybble of port B used to connect to J3
;                 ||||||||
;                 |||||||+------------- SCI RXD input from J3, set high as active low when data sent
;                 ||||||+-------------- SCI TXD output to J3,  set high as active low when data sent
;                 |||||+--------------- J3 GPS_FIX pin input from J3, gets polled, GPS fix is active low
;                 ||||+---------------- Relay control bit, output, see below
;                 |||+----------------- not used
;                 ||+------------------ not used
;                 |+------------------- not used
;                 +--------------------    not used

; configure port A and B data direction registers

            mov    #%11111111,PTADD             ;mask for Port A data direction register
;                 ||||||||
;                 |||||||+------------- not used, set all high as outputs
;                 ||||||+-------------- not used
;                 |||||+--------------- not used
;                 ||||+---------------- not used
;                 |||+----------------- not used
;                 ||+------------------ not used
;                 |+------------------- not pinned out
;                 +--------------------    not pinned out

            mov    #%11111010,PTBDD             ;mask for Port B data direction register
;                 ||||||||
;                 |||||||+------------- SCI RXD input from J3, clear bit for input
;                 ||||||+-------------- SCI TXD input to J3, set bit for output
;                 |||||+--------------- J3 GPS_FIX pin input, clear bit for input
;                 ||||+---------------- Relay control bit, set bit high for output
;                 |||+----------------- not used, set all high as outputs
;                 ||+------------------ not used, set all high as outputs
;                 |+------------------- not used, set all high as outputs
;                 +--------------------    not used, set all high as outputs


; enable pullups on RXD and GPS_Fix inputs, this is only for the demo board to protect floating inputs
; if wires become disconnected
         
            lda    #%00000101
            sta PTBPE

; keep this in your code, it improve system clock accuracy, see ch. 10 of QG8 users manual

;************************************************************************************************
; used to trim frequency of ICS with trim value                                                      ;
;************************************************************************************************
 
        lda     $FFAE               ;get fine trim bit from flash memory
        and     #%00000001         ;only enable the lsb, FTRIM bit
        sta     ICSSC               ;save bit in ICS Status and Control register
        lda     $FFAF               ;get 8 bit trim from flash memory
        sta     ICSTRM             ;save in ICS Trim Register
           


; this starts when the GPS_Fix pin goes high. You will have to poll this pin in your code. When it stays high for
; some time period enable the MTIM interupts and start incrementing the timer chain below. These are the variables
; from the NMEA string
; I did not include day month year

; enable modulo MTIM timer to generate 100 ms interupts
; this supplies system counter chain with a precise time base for counting and timing operations

            mov     #%11000011,MTIMMOD  ;load modulo counter value, do not change, 11000011 makes 10.0Hz MTIM IRQ's
            mov     #%00010011,MTIMCLK  ;select XCLK, prescale div 4, provides 100ms MTIM TOF IRQ's
            mov     #%01100000,MTIMSC   ;enable overflow interupts, reset and make counter active

            cli                            ;global enable interrupts


Standby:    wait                           ;wait for 100ms modulo timer interupt to execute Main Loop      
         
         
; the lines below can deleted, used for toggling the lamp control bit
; the on board green LED is set on for 15ms every 100ms showing the 100ms. MTIM IRQ is running
; for testing your code I would set PTBD3 high to show the switch on time in the PM, in the AM it will cleared low and turn off
; PTBD3 is the output of your algorithm, in the J3 prototype board setting this bit high turns lamp relay on turning off lamp
; clearing it turn the lamp on so you have to invert the sense of the bit when we get the J3 prototype board built

            bset    3,PTBD
            lda    #50                    ;load delay value
            jsr    DLYXMS                ;call delay routine
            bclr    3,PTBD
            bra    Standby

; here out of wait mode every 100 ms from MTIM IRQ's to run counter chain


Inc_100ms_Cnt
        lda     MS_100_Cnt        ;get 100 ms count value
            inca                       ;increment value
            sta     MS_100_Cnt         ;save updated value
            cbeqa   #10,Inc_Sec_Cnt     ;is count equal to 10, 1 second?
            bra     Standby        ;no, stay in this loop until terminal count is reached

; this is how the variables from the NMEA string are incremented when the GPS_Fix pin goes high.
; when it returns low just keep updating these variables from the incoming RXD stream from the J3

; here when 100ms counter counter has reached a count of 10, increment seconds counter

Inc_Sec_Cnt
            clr     MS_100_Cnt         ;clear 100ms counter to zero
            lda     Sec_Cnt             ;get seconds count value
            inca                       ;increment value
            sta     Sec_Cnt             ;save updated value
            cbeqa   #60,Inc_Min_Cnt     ;is seconds count equal to 60?
            bra     Standby                  ;no, stay in this loop until terminal count is reached

; here when seconds counter has reached a count of 60

Inc_Min_Cnt clr     Sec_Cnt             ;clear seconds counter to zero
            lda     Min_Cnt             ;get minutes count value
            inca                       ;increment value
            sta     Min_Cnt             ;save updated value
            cbeqa   #60,Inc_Hour_Cnt     ;is minutes count equal to 60?
            bra     Standby                  ;no, stay in this loop until terminal count is reached

; here when minutes counter has reached a count of 60

Inc_Hour_Cnt clr    Min_Cnt             ;clear hour counter to zero
            lda     Hour_Cnt           ;get hour count value
            inca                       ;increment value
            sta     Hour_Cnt           ;save updated value
            cbeqa   #24,Inc_Hour_Cnt     ;is hours count equal to 24?
            bra     Standby                  ;no, stay in this loop until terminal count is reached

; can delete, just used for the LED demo board

;************************************************************************************************
; SUBROUTINE:   DLYXMS                                                                         ;
; CALLED FROM:     Test sequence.                                                                    ;
; ON ENTRY:     A contains number of milliseconds to delay.                                     ;
; ON RETURN:    A and X are zero.                                                               ;
; DESCRIPTION:  Provides a delay in milliseconds equal to the value in A times 4.                 ;
;                Loading A with 4 provides a delay of 1ms. A value of 8 would give 2ms             ;
;               The inner loop delays 250us. Outer loop counts # of ms x 4                       ;
;************************************************************************************************

DLYXMS        EQU    $                         ;return here when outer loop done
            LDX     #$D8                   ;load delay value in X for inner loop
DLYXMS1     EQU     $                     ;return here when inner loop not done
            DECX                           ;decrement delay counter
            NOP                           ;burn two bus cycles
            BNE     DLYXMS1                ;branch if not zero
            DECA                           ;decrement value in A every 250us
            BNE     DLYXMS                 ;until zero, branch if not done
            RTS

; you will need this in your code

;************************************************************************************************
; Timer Chain Modulo Timer Overflow Interupt Service Routine                                   ;
;************************************************************************************************

; modulo timer over flow interupt used for 100ms time base

_Vmtim:     lda     MTIMSC              ;read modulo timer status and control register to clear TOF
            mov     #%01100000,MTIMSC   ;enable TOF interupts, reset and start timer
            rti

;**************************************************************
;* spurious - Spurious Interrupt Service Routine.             *
;*             (unwanted interrupt)                           *
;**************************************************************

spurious:                ; placed here so that security value
            NOP            ; does not change all the time.
            RTI

;**************************************************************
;*                 Interrupt Vectors                          *
;**************************************************************

           ORG       $FFE6
            DC.W     _Vmtim                ;MTIM over flow interupt

            ORG        $FFFA
            DC.W     spurious            ; IRQ
            DC.W     spurious            ; SWI
            DC.W     _Startup            ; Reset



And here is what we have, just trying to get the ASCII characters into the data buffer:
C:
/******************************************************************************
*       Copyright (C) 2005 Freescale Semiconductor, Inc.
*       All Rights Reserved
*
* Filename:     DEMO9S08QG8_Test.c
* Author:       r1aald
* Revision:     1.0
*
* Description:  This is the test code that will reside in the QG8 demo
*                to provide an out of the box experience. This simple code
*                blinks LED2 and toggles LED1 when SW1 is pressed.
*
* Notes:        Also serves as an example for the 9S08QG8 demo board.
*               Created using CodeWarrior 5.0 for HC(S)08.
******************************************************************************/


#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "demo9S08QG8.h" /*include demo board declarations */
   


void InitPorts()
{
  // Enable pull-ups on all input pins
  //PTAPE = 0xFF;
  //PTBPE = 0xFF;
  PTAD = 0b00010000;
  PTBD = 0b00001011;
  PTADD = 0b11011111;
  PTBDD = 0b11111010;
  SCIBDH = 0b00000000;
  SCIBDL = 0x33;
  SCIC1 = 0b00000000;
  SCIC2 = 0b00101100;
  //SCIS1 = 0b00000000;
  SCIS2 = 0b00000000;
  SCIC3 = 0b00000000;
  SCID = 0b00000000;
}    //end InitPorts

char RecChar()
{
  byte rec_char;

  if (SCIS1_RDRF)  // 1st half of RDRF clear procedure
    rec_char = SCID;  // 2nd half of RDRF clear procedure
 
  SCIC2_RE = 1;    // enable Rx
  while(!SCIS1_RDRF)
  {
    __RESET_WATCHDOG();
  };
  rec_char = SCID; // get recieved character
  //SendChar(rec_char); // echo received character
  return SCID;
}



void main(void)
{
  byte rec_char;

  DisableInterrupts;
  asm
  {
    rsp
    };
  InitPorts();
  SOPT1 = 0b11100011;       // b7 COP enabled, long timeout, stop mode enabled pta4 is output
  //***
  // I think something needs to be cleared before data will be sent
  // not sure what though
  //***
  if (SCIS1_RDRF)  // 1st half of RDRF clear procedure
  {
    rec_char = SCID;  // 2nd half of RDRF clear procedure
  }
 
  SCIC2_RE = 1;    // enable Rx
  SCIC2_ILIE = 1;  // enable receiver interrupt
 
  EnableInterrupts; /* enable interrupts */


  //***
  // this is all stuff for the LED demo I'm leaving in here
  //***
//  ICSC2_BDIV = 3;
//  LED1 =0;
//  LED2 =0;   /* Port B7 is connected to LED 2 */
  //PTBDD_PTBDD7 = 1; /* Set PTB7 as an output */
  //PTBDD_PTBDD6 = 1;        
  /** mtim_setup */
  //MTIMCLK_PS = 8;
  //MTIMCLK_CLKS = 0;
  //MTIMMOD = 112;
  //MTIMMOD = 0;    /* modulo = 50 */
  //MTIMSC = 0x60;  /* reset and start MTIM, enable ints */
  /** KBI Set Up foe SW1 */
  //KBIPE_KBIPE2 =1; /* Enable Keyboard Pin */                                
  //KBISC_KBIE = 1;  /* Enable Keyboard Interrupts */
  //KBISC_KBACK = 1; /* Clear Pending Keyboard Interrupts */
  //PTAPE_PTAPE2 = 1; /* Enable Pullup for Keyboard pin */
           
  for(;;)
  {
    __RESET_WATCHDOG(); /* feeds the dog */
  } /* loop forever */
}



/** KBI ISR */

//interrupt 18 void   KBI_ISR(void)
//{
//  KBISC_KBACK = 1; /* Clear Pending Keyboard Interrupts */
//  LED1 = ~LED1;    /* toggle Port */
//}


/** MTIM_ISR - ISR that accompanies the MTIM PWM routine. */
//interrupt 12 void   MTIM_ISR(void) {
//  MTIMSC_TOF=0;     /* clear TOF */
//  LED2 = ~LED2;     /* toggle Port */
//}


interrupt VectorNumber_Vscirx void  VSCIRX_ISR(void)
{
  //***
  // I'm not really doing anything here... I just needed a place to put a breakpoint
  // to see if it ever enters this interrupt function
  //***
  char  input;
  RecChar();
}
Additional Info:

We are using Freescale Demo Board DEMO9S08QG8E
(data sheet: http://cache.freescale.com/files/microcontrollers/doc/user_guide/DEMO9S08QG8UG.pdf )
Quick Start Guide: http://cache.freescale.com/files/microcontrollers/doc/user_guide/DEMO9S08QG8QSG.pdf

CodeWarrior v. 5.9.0

Any assistance will be appreciated.

Moderators note: used code tags
 
Last edited by a moderator:

MrChips

Joined Oct 2, 2009
21,159
Here is a working example of receiving serial data into a buffer at 9600 baud using receiver interrupts.
Use parts of this code as you see fit.
In this example, the buffer is set for 16 characters. When either the buffer is full or a terminator character is received a flag is set.
Alter to suit.

I tested this by looping back the TX data into the RX data.

Code:
/***************************************************************

    Serial Demo
    Written by: MrChips
    Date: 2017.03.21

****************************************************************/

#include <hidef.h>
#include <MC9S08QG8.h>

/***************************************************************
    Constants
****************************************************************/

#define NUL      0
#define TERMINATOR 0x0D   // Carriage Return
#define RDIMAX   16       // max RX index
#define RX_IRQ_VECTOR_NUMBER 15

/***************************************************************
    Globals
****************************************************************/

char RD_buffer[RDIMAX + 1];
byte RDi, RD_available, Test_byte;


/***************************************************************
    Prototypes
****************************************************************/

void putc(char ch);
void delay(long int d);

/***************************************************************
    Serial Functions
****************************************************************/

void putc(char ch)
{
  while (SCIS1_TDRE == FALSE);
  SCID = ch;
}

void interrupt RX_IRQ_VECTOR_NUMBER SCI_RD_ISR(void)
{
  byte b;
  // to clear RDRF, read SCIS1 and read SCID
  b = SCIS1;
  b = SCID & 0x7F; // 7-bit ASCII only
  if ( (RDi >= RDIMAX) || (b == TERMINATOR) )
    {
      RD_available = TRUE;
    }
    else
    {
      RD_buffer[RDi++] = b;    // pack data into buffer
      RD_buffer[RDi]   = NUL;  // insert NUL
    }
}

void Parse(void)
{
  // parse input data
  RDi = 0;
  RD_available = FALSE;
  // insert your code here
}

/***************************************************************
    Misc Functions
****************************************************************/

void delay(long int d)
{
  long int i;
  i = 0;
  while (++i < d);
}

void init(void)
{
  SOPT1 = 0x52;         // disable COP watchdog while testing code
  PTBDD = 0b00001000;   // set ports, for debug

  // init SCI
  /*---------------------------------------------------------
    --------------  !!! note !!! ----------------------------
     for accurate and stable baud frequency,
     use 8MHz XTAL on pins 5 and 6
     ICSC1 = 0x80;
     ICSC2 = 0x36;
  ------------------------------------------------------------*/
  SCIBDH = 0;
  SCIBDL = 26;          // 26 for 9600b
                        // 52 for 4800b
  SCIC2  = 0b00101100;  // enable TX, RX, RIE
  // initialize
  RDi = 0;
  RD_available = FALSE;
  Test_byte = 'A';
  EnableInterrupts;
}

/***************************************************************
    main program
****************************************************************/

void main(void)
{
  init();

  //-------------------------------------
  // endless loop
  for(;;)
  {
    __RESET_WATCHDOG();

    if (RD_available)
    {
      Parse();
    }

    putc(Test_byte++);        // loop back test
    delay(10000);             // 1-second delay

   }
  // endless loop
   //-------------------------------------

}

/***************************************************************
    end of program
****************************************************************/
 

Thread Starter

mgookin

Joined Mar 21, 2017
11
A very sincere thank you.
Today we saw the data come through.
We've adjusted the parameters to accompany the string and it's coming along very nice.
Thanks again.
 
Top