Skip to main content
Knowledgebase
Home
Renesas Singapore - Knowledgebase

What is the dynamic display methods for LEDs (78K0/Kx2, 78K0S/Kx1+)?

Latest Updated:11/01/2007

Question:

Dynamic display methods for LEDs (78K0/Kx2, 78K0S/Kx1+)

Answer:

[Introduction]
Dynamic display methods are used for displaying a lot of information. See also the FAQ section entitled "Dynamic and static".
The following describes the dynamic display method used for the circuit that was described as the figure "Example of matrix connection for LEDs" in the FAQ section entitled "LED drive methods" category.



[Display method]
Here, 16 LEDs are divided into four groups: L1 to L4, L5 to L8, L9 to L12, and L13 to L16. In P44 to P47, 0 is set to the ports corresponding to the LED groups including the LEDs to be turned on, and 1 is set to the other ports. P40 to P43 are used to specify the LEDs to be turned on. As shown in the figure below, 0 is set to P44, P45, P46, and P47 in that order, for low-level output from those ports. In combination with this, the corresponding LED turning-on pattern is output to P40 to P43.


The display is switched every 2.5 ms, so that within 10 ms (when at 100 Hz) turning on of the whole LEDs is completed. Consequently, the system clock is used as a 4 MHz clock that is generated by dividing 8 MHz high-speed internal oscillation clock by 2. This clock is also divided by 64 for count clock of the 8-bit timer. Additionally, the count clock is divided by 156 with the 8-bit timer to generate interval interrupts at approximately 400 Hz. The display is changed in these interval interrupt servicing.

[Sample program 1]
The following shows a sample program (for 78K0S/Kx1+) coded in assembly language. A sample program in C language is shown in sample program 2.
To specify a display, two 8-bit LED status variables (LEDSTATUS1 and LEDSTATUS2) corresponding to the LEDs to be turned on are provided, and the display data is set to these variables. During the timer interrupt servicing, the data corresponding to four LEDs is extracted from the bits corresponding to the LEDs to be turned on. This data is combined with the data specifying the display groups and then output to port 4 to turn on LEDs. This is repeated four times to complete the display.

• Generation of display data
To divide the LED status information into four groups before turning on LEDs, a display data pattern is extracted from the LED status based on the information indicating which of the four display iterations has been specified. To generate the display data, information indicating which of the four groups has been specified is generated by the X register and information indicating which LED is to be turned on is generated by the A register, and then these are combined. Processing time is shortened by performing parallel processing of the information indicating the LED group and the information indicating the LEDs to be turned on, and then combining these processing results. The sample program shown below mainly contains processing of group selection information from the X register and processing of the specific LED turning-on information from the A register.

DATWORK         DSEG    SADDR
NEXTDATA:       DS      1               ; For storing next display data
LEDSTATUS1:     DS      1               ; Information for turning on LED1 to LED8
                                        ;  (1 = ON)
LEDSTATUS2:     DS      1               ; Information for turning on LED9 to LED16 
                                        ;  (1 = ON)
COUNT:          DS      1               ; Display iteration information (0 to 3)

GETLED:
                MOV     A,LEDSTATUS1    ; Read status of LED1 to LED8
                MOV     X,#11101111b    ; Select signal for LED1 to LED4 
                BF      COUNT.1,$NEXT1  ; Branch to NEXT1 if LED1 to LED8 are displayed
                MOV     A,LEDSTATUS2    ; Otherwise, Read status of LED9 to LED16
                MOV     X,#10111111b    ; Select signal for LED9 to LED12
NEXT1:
                BF      COUNT.0,$NEXT2  ; Branch if LED1 to LED4 or LED9 to LED12
                ROR     A,1             ; Set valid LED bits to lower 4 bits
                ROR     A,1
                ROR     A,1
                ROR     A,1
                XCH     A,X             ; Send group select signal to A register
                ROL     A,1             ; Shift select signal to next group
                XCH     A,X             ; A:LED status, X:Group information 
NEXT2:
                OR      A,#11110000b    ; Mask group information 
                AND     A,X             ; Combine display data
                MOV     NEXTDATA,A      ; Save next display data
                RET

• Display of data (timer interrupt servicing)
Each group of LEDs is turned on using interrupts that are generated every 2.5 ms.
The subroutine shown above is used to generate the data to be displayed.
First, the current display is deleted, then the data that was previously calculated is output to a port to execute the display. Afterward, the next group is selected and its display data is set up.
The reason why previously calculated data is used is to minimize any timing variation effects.

TMH1INT:
                PUSH    AX
                MOV     A,NEXTDATA      ; Read display data information
                MOV     P4,#11110000b   ; Turning off all LEDs
                MOV     P4,A            ; Display new data
                INC     COUNT           ; Select next group
                MOV     A,#00000011b    ; Mask number of groups displayed.
                AND     A,COUNT         ; If all columns have been completed,
                MOV     COUNT,A         ; set next group.
                CALL    !GETLED         ; Generate next display data.
                        :
        Other required processing is coded here.
                        :
                POP     AX
DUMMY:          RETI                    ; End of interrupt servicing

• Initialization processing
Initialization processing includes setting the stack pointers, waiting for power supply activation, and initializing memory and other on-chip peripheral hardware that is used. Afterward, the timer is started and interrupt masking is canceled, then other processing is performed. When a timer interrupt occurs, the LED display starts.
The reset vectors and interrupt vectors are programmed as shown below. Dummy vectors are set so that the results for unused interrupts are returned by a RETI instruction, without performing any processing for them.

RSTVECT CSEG    AT      0
                DW      START           ;00:Vector for reset start processing 
                DW      DUMMY           ;02:
                DW      DUMMY           ;04:
                DW      DUMMY           ;06:INTLVI
                DW      DUMMY           ;08:INTP0
                DW      DUMMY           ;0A:INTP1
                DW      TMH1INT         ;0C:INTTMH1
                DW      DUMMY           ;0E:INTTM000
                DW      DUMMY           ;10:INTTM010
                DW      DUMMY           ;12:INTAD
                CSEG
START:          MOVW    AX,#STACKP
                MOVW    SP,AX
                CALL    !POWERON        ; Wait for power supply activation
                CALL    !INITIO         ; Hardware initialization 
                CALL    !INITRAM        ; RAM initialization 
                        :
                        :
                SET1    TMHE1           ; Start timer
                CLR1    TMMKH1          ; Cancel masking of timer interrupts
                EI
                        :
        Other desired processing is coded here
                        :

;
;       Wait for power supply activation 
;       (wait until power supply voltage reaches at least 2.7 V)
;
POWERON:
                DI
                MOV     LVIS,#00000111b ; VLI=2.7V
                MOV     LVIM,#10000000b ; Start low voltage detection 
                MOV     PCC,#00         ; CPU clock is fx/4
                MOV     WDTM,#01110000b ; Stop WDT
                SET1    LSRSTOP         ; Stop low-speed internal oscillator 
                MOV     A,#50
PONLOOP:
                DEC     A
                BNZ     $PONLOOP        ; Wait more than 0.2 ms

PONLOOP2:
                BT      LVIF,$PONLOOP2  ; Wait for power supply voltage to reach 2.7 V
                MOV     PPCC,#01        ; CPU clock is fx/2
                RET
;
;       RAM initialization 
;
INITRAM:
                MOV     COUNT,#3
                MOV     LEDSTATUS1,#0
                MOV     LEDSTATUS2,#0
                MOV     NEXTDATA,#11110000b
                RET
;
;       Hardware initialization settings for timer H1, port 4, etc.
;
INITIO:
                MOV     P4,#11110000b           ; Initial value (all LEDs off)
                MOV     PM4,#00                 ; Port 4 set to all output 
                MOV     TMHMD1,#00110000b       ; Timer mode setting
;                                |||++-----   Interval timer mode
;                                +++-------   Count clock fXP/64
                MOV     CMP01,#155              ; Set interval period
                MOV     IF0,#00                 ; Clear interrupt
                        :
        Other required initialization processing is coded here
                        :
                RET


[Sample program 2]
The following describes an example of an LED display program coded in C language. In this example, there is additional processing that adds 1 to the display pattern about once per second.

• Declarations
Since this program controls interrupts except during I/O operations involving on-chip peripherals, a #pragma directive is declared at the start of the program, as shown below. In the prototype declaration, GETLED is declared as the function that performs interrupt servicing.

Coffee break

In the C language that is used for 78K Series products, certain functions are expanded for embedded uses within the standard C language. Declarations are required to enable use of these expanded functions. The main declarations are "#pragma SFR", used as a key word for on-chip peripheral I/O operations, as well as "#pragma EI", "#pragma NOP", and other directives that specify how various CPU instructions will be used in C language programs. Finally, the "#pragma INTERRUPT INTTMH1 GETLED" directive is used to combine the CPU's vector interrupt (in this case, INTTMH1) with the actual processing function (in this case, GETLED).


In addition, in the prototype declaration, hdwinit is declared to perform hardware initialization.
As a variable, LEDSTATUS contains information on LEDs to be turned on, and in this case it is processed as a 16-bit variable. SECTIMER is used to count one second of time. NEXTDATA and COUNT are used with the same meaning they have in assembly language programs.

#pragma SFR
#pragma EI
#pragma DI
#pragma NOP
#pragma INTERRUPT INTTMH1 GETLED

unsigned int LEDSTATUS,SECTIMER;
unsigned char NEXTDATA,COUNT;

__interrupt void        GETLED(void);
void    hdwinit(void);


• Initialization processing block
In the 78K's C language program, initialization processing for on-chip peripheral I/O operations can be performed before the main part of the program is executed. The special-purpose function (hdwinit) is reserved for this purpose. The tasks that must be processed early on are coded in the hdwinit function.

Coffee break

In an "All Flash" type of 78K microcontroller, the hardware configuration is determined by referencing the option byte when the CPU is started. Afterward, execution starts from the address stored in the reset vector (addresses 0 and 1). In an assembly language program, the reset vector is coded as part of the program, but in a C language program, a startup routine is used instead. For further description of this startup routine see the FAQ section entitled"First execution tasks".
The startup routine performs the setting of the stack pointer and other processing needed to execute C language programs. This routine includes a hdwinit function call. Once this series of processing has been completed, the startup routine calls the main function coded in C language to execute the C language program.


The hdwinit function shown below first stops the watchdog timer, then uses low voltage detection to wait for the power supply voltage to rise. Once low voltage detection has started, it takes 0.2 ms before accurate results can be obtained, and a software timer is used for this wait operation. When the power supply voltage reaches at least 2.7 V, the CPU's operating clock is set to 4 MHz and the target ports, timers, etc. are initialized.

void    hdwinit(void){
        unsigned char work1;

        LVIS = 0b00000111;              /* select VLI=2.7V        */
        LVIM = 0b10000000;              /* Start VLI detection    */
        PCC = 0x00;                     /* CPU clock is fx/4      */
        WDTM = 0b01110000;              /* Stop WDT               */
        LSRSTOP = 1;                    /* Stop Low speed OSC     */

/*
        wait for 0.2ms
*/
        for (work1 = 0; work1 < 10; work1++){
                NOP();
        }

        while ( LVIF ){
                NOP();
        }                               /* wait VDD > 2.7V         */

        PPCC = 0b00000001;              /* CPU clock is fx/2       */
        P4 = 0b11110000;                /* Clear All LED           */
        PM4 = 0x00;                     /* Port 4 is Output        */

        TMHMD1 = 0b00110000;            /* set interval timer mode */
        CMP01 = 155;                    /* Interval = 2.5ms        */
        IF0 = 0x00;
}


• Main processing block
The main function sets initial values for variables. Afterward, it starts the time and waits for the variable that counts one-second periods (SECTTIMER) to reach a value of 0. When one second has elapsed, 1 is added to the display data (LEDSTATUS) value. Data is written to the SECTIMER variable from both the main function and the interrupt function, so exclusive control should normally be used for this. However, exclusive control (in this case, enabling or prohibiting interrupts) is not performed here since processing is completed within the interrupt interval (2.5 ms).

void    main(void){
        COUNT = 3;
        NEXTDATA = 0b1111000;
        LEDSTATUS = 1;
        SECTIMER = 400;
        TMHE1 = 1;
        TMMKH1 = 0;
        EI();
        while(1){
                while(SECTIMER){
                NOP();
                }
                SECTIMER = 400;
                LEDSTATUS++;
        }
}

• Interrupt servicing block
Interrupts are triggered and executed every 2.5 ms using timer H1. Consequently, "__interrupt" is declared at the start of functions to indicate when the function is an interrupt servicing function. Otherwise, these functions are similar to functions that do not include arguments or return values.
Most of the processing concerns the generation of data patterns that are output to ports to set up displays. One such function is to generate a select signal for the group that corresponds to the groups to be displayed. This function is implemented by using a switch statement in which values are set to NEXTDATA according to the COUNT variable. Another function extracts display data. The data to be displayed (LEDSTATUS) is right-shifted precisely the required number of times, and data other than the lower four bits is masked to implement this function. The two sets of data acquired in this way are then combined to form a data pattern for the next display.
Other processing includes outputting the previously generated data pattern to a port, updating the display group for the next display, and counting out another second.

__interrupt     void    GETLED(void){
        unsigned int work1;
        unsigned char work2;
        P4 = 0b11110000;                /* Clear LED         */
        P4 = NEXTDATA;                  /* Turn on specified LED */
        work1 = COUNT;                  /* Get Display Group Number */
        switch(work1){
                case 0:
                                NEXTDATA = 0b11100000;
                                break;
                case 1:
                                NEXTDATA = 0b11010000;
                                break;
                case 2:
                                NEXTDATA = 0b10110000;
                                break;
                case 3:
                                NEXTDATA = 0b01110000;
        }
        work1 *= 4;
        work2 = LEDSTATUS >> work1;
        work2 &= 0b00001111;
        work1 = (unsigned char) work2;
        NEXTDATA |= work1;
        COUNT = (COUNT+1) & 0b00000011;
        SECTIMER--;
}
Suitable Products