Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

PIC18f2550 SSPBUF problem in assembly

Status
Not open for further replies.

Jiadong Yao

Member level 1
Member level 1
Joined
Mar 19, 2014
Messages
40
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Visit site
Activity points
278
Hello,everyone.

i am doing the lab. but i have some problems now.
The requirement is
1. make a counter
2.Configure your PIC as a Master SPI.
3. Transmit the counter values via the SPI Master. Connect SDO directly to SDI of the same board. Check what happens.
4. Display the received 8-bit result on 8 LED’s. Contrary to what was done in the previous exercise, the LED’s must be driven by results received via SPI, not via direction connection to PORTB. Display the SPI data line on an oscilloscope

here is my code
Code:
	#include	<p18F2550.inc>

    counter equ  0x21
    delay   equ  0x22
    delay1 equ 0x23
    delay2 equ 0x24
    delay3 equ 0x25



;***********************************************************
; 					    Reset Vector
;***********************************************************

	ORG		0x800			; Reset Vector
							; When debugging:0x000; when loading: 0x800
	GOTO	START


;***********************************************************
; 					    Interrupt Vector
;***********************************************************



	ORG     0x808	; Interrupt Vector  HIGH priority
	GOTO 	inter	; When debugging:0x008; when loading: 0x808
                    ; 808high 818low



;***********************************************************
;				 Program Code Starts Here
;***********************************************************

	ORG		0x820			;When debugging:0x020; when loading: 0x820

START

    clrf 	PORTA 		; Initialize PORTA by clearing output data latches
	movlw 	0x39 		      ; Value used to initialize data direction
	movwf 	TRISA 		; Set RA0,3,4 as inputs  0001 1001
	movlw 	0x0F 			; Configure A/D for digital inputs 0000 1111
	movwf 	ADCON1 		;
    movlw 	0x07 			; Configure comparators for digital input
	movwf 	CMCON
	clrf 	PORTB 		; Initialize PORTB by clearing output data latches
	movlw 	0x01 			; Value used to initialize data direction
	movwf 	TRISB 		; Set PORTB as output
	clrf	PORTC 		; Initialize PORTC by clearing output data latches
	movlw 	0x00	    		; Value used to initialize data direction
	movwf 	TRISC

	bcf		UCON,3		; to be sure to disable USB module  p.166 why disable USB module??
	bsf		UCFG,3		; disable internal USB transceiver p.168

    movlw   0x00
    movwf   SSPSTAT     ;sampled at middle
                         ;transition from Idle to active
                         ;Idle state for clock is a low level

    movlw   0x22         ;SPI Master mode, clock = FOSC/64
    movwf   SSPCON1
               
  


    clrf	counter			; clear registers
    movlw   0xff
    movwf   delay
    movwf   delay1
    movwf   delay2
    movwf   delay3

    movlw   0x12  ;125KHz
    movwf   OSCCON



main
	btfsc       PORTA,3         ;if RA3=0, skip, go to main
    goto        select            ;if RA3=1, go to select
    goto        main

select
    btfsc   	PORTA,4      ;check RA4, if it is equal 1, go to up
	goto 		up           ; else go to down
    goto    	down

up          				; up counter
    movlw   	0xff         	;move the 255 to W
    cpfslt      counter     ; compare counter with W, skip if less than 255
    goto        up1
    goto        up2
up1
    clrf    	counter     ; clear, counter = 0
    movf        counter,0   ;show on PORTB
    btfsc       PORTA,0     ;test RA0
    goto        main
 
    goto        SPIsend

up2
    incf    	counter,1   ;increment
    movf        counter,0   ;show on PORTB
    btfsc       PORTA,0     ;test RA0
    goto        main

    goto        SPIsend

down                        ;down counter
    movlw    	0x00            ; move 0 to the W
    cpfsgt     	counter        ;compare counter with W, skip if great than 0
    goto        down1          ;
    goto        down2
down1
    movlw    	0xff     ; set counter = 255
    movwf       counter
    movf        counter,0   ;show on PORTB
    btfsc       PORTA,0     ;test RA0
    goto        main

    goto        SPIsend

down2
    decf        counter,1
    movf        counter,0   ;show on PORTB
    btfsc       PORTA,0     ;test RA0
    goto        main

    goto        SPIsend



delay_loop
    Decfsz      delay,1
    goto        $+2
    decfsz      delay1,1
    goto        $+2
    decfsz      delay2,1
    goto        $+2
    decfsz      delay3,1
    goto        delay_loop
    return

SPIsend
    movwf   SSPBUF

    goto    main

SPIread
    bcf     PIR1,SSPIF
    MOVFF   SSPBUF,PORTB
    call    delay_loop
    RETURN
inter                       ;interrupt doesn't occur
    BTFSC   PIR1,SSPIF
    call    SPIread
    RETFIE

END

Because RB0 is used as SDI, and RB1 is used as SCK, only RB2 to RB7 will be used to display the LEDs
This lab is quite strange. We use one pic as a master, but it connects itself.
Does that mean it is both master and slave ? then how does the CLK to be connected? (I just connect it to the ground, indeed, it will blink very fast. Fosc=125KHz)

But there is no LED on from RB2 to RB7. I think it means that the interrupt does not occur. How to solve the problem?

Help!
 

Connecting pins configured as output to ground may damage the device.
When MOSI pin sends the data, MISO pin triggering incoming data. In case of loop it will recieve exaclty what being send.
 

Connecting pins configured as output to ground may damage the device.
When MOSI pin sends the data, MISO pin triggering incoming data. In case of loop it will recieve exaclty what being send.

Actually, i connect the clk pin to the ground via a LED

Well, I understand what you said. But it doesn't help. Do i made any mistake in the code? I dont know why the interrupt doesn't occur.
 

Where is your new code. If possible Zip and post the complete MPLAB or MPLABX MPASM project files.
 

Attachments

  • Lab3-masterMode.X.zip
    36.2 KB · Views: 115
  • QQ截图20141116144030.png
    QQ截图20141116144030.png
    30.4 KB · Views: 124

You need to write a counter program. It doesn't have anything to do with SPI communication.
 

You need to write a counter program. It doesn't have anything to do with SPI communication.

The requirement is
1. make a counter
2.Configure your PIC as a Master SPI.
3. Transmit the counter values via the SPI Master. Connect SDO directly to SDI of the same board. Check what happens.
4. Display the received 8-bit result on 8 LED’s. Contrary to what was done in the previous exercise, the LED’s must be driven by results received via SPI, not via direction connection to PORTB. Display the SPI data line on an oscilloscope

- - - Updated - - -

You need to write a counter program. It doesn't have anything to do with SPI communication.

WE need to use one pic to both transmit and receive the counter value
 

So, there will be two PICs right? One master and one slave. Master sends counter values to slave PIC and slave PIC displays this data on PORTB. Is that all you want ? Are both PICs 18F2550 ? What clock frequency each PIC is running at ?

Please post your circuit. In your code where is ISR ?
 

There will be only one PIC, that will receivce that what he will send. What circuit do you need? Where MISO connected to MOSI?
 

Ok. I though it was a PIC to PIC communication. Now I got it. I don't know whether one PIC can do that or not because data will be in SSPBUF register and how can the same register be used to send out data one bit at a time and also receive it because for receiving data also the same SSPBUF is required.


If it is a master to slave communication then it can be done. You copy the value of counter to SSPBUF and then increment the counter and send out this data to slave and slave receives this data in SSPBUF register and this SSPBUF register is assigned to PORTx say PORTB to display the counter value. Then there will be a small delay of say 1 second in the master before incrementing the counter.

I don't know how this can be done using a single PIC. Does 18F2550 has two SPIs ? If yes then it can be done.
 
Last edited:

So, there will be two PICs right? One master and one slave. Master sends counter values to slave PIC and slave PIC displays this data on PORTB. Is that all you want ? Are both PICs 18F2550 ? What clock frequency each PIC is running at ?

Please post your circuit. In your code where is ISR ?

No. there is only one pic.
That's why i am confusing

- - - Updated - - -

So, there will be two PICs right? One master and one slave. Master sends counter values to slave PIC and slave PIC displays this data on PORTB. Is that all you want ? Are both PICs 18F2550 ? What clock frequency each PIC is running at ?

Please post your circuit. In your code where is ISR ?

ISR = interrupt service routine if i understand correctly.

In the code, ISPread is the interrupt routine.

- - - Updated - - -

There will be only one PIC, that will receivce that what he will send. What circuit do you need? Where MISO connected to MOSI?

I google your terminology and find MISO and MOSI are data input and data output.
In datasheet, it is called SDO and SDI. SDO is the pin RC7. SDI is pin RB0. so i connected RC7 and RB0.

- - - Updated - - -

Ok. I though it was a PIC to PIC communication. Now I got it. I don't know whether one PIC can do that or not because data will be in SSPBUF register and how can the same register be used to send out data one bit at a time and also receive it because for receiving data also the same SSPBUF is required.


If it is a master to slave communication then it can be done. You copy the value of counter to SSPBUF and then increment the counter and send out this data to slave and slave receives this data in SSPBUF register and this SSPBUF register is assigned to PORTx say PORTB to display the counter value. Then there will be a small delay of say 1 second in the master before incrementing the counter.

I don't know how this can be done using a single PIC. Does 18F2550 has two SPIs ? If yes then it can be done.

I have the same question as you do.
but i am sure that 18F2552 only have one SPI.
 

I used Arduino and tested a SPI loopback code which I wrote. I am attaching it here. I see that what data is sent out of SPI the same data is received by SPI. MSB is being sent out first. I will try with PIC now. First I will write a C code and if it works then I will implement it in ASM.

111404d1416162713-spi-lb.png


- - - Updated - - -

I have done what you want in C code. In your post it was mentioned that the data should be displayed on PORTB when RA0 == 0. It means that hardware SPI cannot be used. So you can use Software SPI. Your professor will not give a project where SPI pins of PORTB should be used a input and output and also as outputs for LEDs. 8 bit counter data has to be output on 8 bit PORTB. I have written a C code. Try to implement it in asm code. The only problem I see is that, I have used a 1 second delay before incrementing or decrementing counter value and so if button connected to RA4 is pressed to toggle the incrementing or decrementing then you need to press and hold the button atleast 1.2 sec and then release it because if the code is executing SPI_Transfer() function and at that time if you press the button then it has to finish the SPI transfer and then execute 1 second delay and then it has to check the button press. PORTB has external interrupts and as it is used for LEDs so INTx pins cannot be used for buttons.

- - - Updated - - -

This is the C code I have written. Implement it in ASM.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Software SPI module connections
sbit SPI_MISO at RC0_bit;
sbit SPI_MOSI at LATC1_bit;
sbit SPI_MISO_Direction at TRISC0_bit;
sbit SPI_MOSI_Direction at TRISC1_bit;
// End Software SPI module connections
 
unsigned char SPIOutData = 0, SPIInData;
char toggleValue = 0;
 
unsigned char SPI_Transfer(unsigned char SPIData) {
     char SPICount, inByte = 0;
 
     for(SPICount = 0; SPICount < 8; SPICount++) {
 
              inByte <<= 1;
              
              if (SPIData & 0x80)
                SPI_MOSI = 1;
              else
                SPI_MOSI = 0;
 
              inByte += SPI_MISO;
              
              SPIData <<= 1;
     }
 
     return  inByte;
}
 
void main() {
 
    ADCON1 = 0x0F;
    CMCON = 0x07;
    CVRCON = 0x00;
    
    TRISA = 0xFF;
    TRISB = 0x00;
    TRISC = 0x00;
    
    SPI_MISO_Direction = 1;
    SPI_MOSI_Direction = 0;
 
    while(1) {
 
          if(!PORTA.F3) {
               Delay_ms(50);
               if(!PORTA.F3) {
               
                    SPIInData = SPI_Transfer(SPIOutData);
                    
                    if(!PORTA.F0) {
                         Delay_ms(50);
                         if(!PORTA.F0) {
                                LATB = SPIInData;
                         }
                    }
          
                    if(!PORTA.F4) {
                         Delay_ms(50);
                         while(!PORTA.F4);
                         toggleValue = ~toggleValue;
                    }
 
                    if(!toggleValue)++SPIOutData;
                    else if(toggleValue)--SPIOutData;
 
                    Delay_ms(1000);
               }
          }
    }
}



- - - Updated - - -

I will try to implement Hardware SPI Communication in C. If it works I will post it and you can implement it in ASM. The Arduino SPI library which I used used hardware SPI and interrupts.

I have read the datasheet of PIC18F2550 and your project can be done but PORTB cannot be used to output 8 bit data if hardware SPI is used. There is no need for clock to transfer data. Only SDI and SDO pins are needed for loopback.

- - - Updated - - -

See if this code works. Add the code related to buttons.


Code ASM - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
counter equ  0x21
d1      equ 0x22
d2      equ 0x23
d1_2    equ 0x24
        
 
    org 0x0000
 
START
 
    movlw   0x0F
    movwf   ADCON1
    movlw   0x07
    movwf   CMCON
    clrf    CVRCON
    movlw   0xFF
    movwf   TRISA
    movlw   0x01
    movwf   TRISB
    clrf    TRISC
    clrf    PORTA
    clrf    PORTB
    clrf    PORTC
    clrf    SSPSTAT
    movlw   0x22
    movwf   SSPCON1
    clrf    counter
 
main
    call    SPI_Transfer
    rlcf    W
    rlcf    W
    movwf   PORTB
    call    Delay
    incf    counter
    goto        main
 
SPI_Transfer
       movwf   SSPBUF
wait   btfss   SSPSTAT,BF
       bra     wait
       movf    SSPBUF,W
       return
 
;Delay = 1 seconds
;Clock frequency = 4 MHz
 
; Actual delay = 1 seconds = 1000000 cycles
; Error = 0 %
 
Delay
                        ;999990 cycles
        movlw   0x07
        movwf   d1
        movlw   0x2F
        movwf   d2
        movlw   0x03
        movwf   d1_2
Delay_0
        decfsz  d1, f
        goto    $+2
        decfsz  d2, f
        goto    $+2
        decfsz  d1_2, f
        goto    Delay_0
 
                        ;6 cycles
        goto    $+1
        goto    $+1
        goto    $+1
 
                        ;4 cycles (including call)
        return
 
    end

 

Attachments

  • ardu_spi_lb.rar
    39.9 KB · Views: 105
  • spi lb.png
    spi lb.png
    25.8 KB · Views: 135
  • PIC18F2550 SPI.rar
    65.5 KB · Views: 97

I have implemented what you want in HW SPI C code and it is working fine. PORTB is used to display received SPI data. RB2-RB7 is used to output data and so you can't see 8 bit value on PORTB. SDO is connected to SDI. Code is written in mikroC PRO PIC. Just study the code and implement it in ASM.

Proteus simulation attached.

- - - Updated - - -


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
unsigned char SPIInData = 0, SPIOutData = 0;
char toggleValue = 0;
 
unsigned char HW_SPI_Transfer(unsigned char SPIData) {
     unsigned char inByte = 0;
 
     SSPBUF = SPIData;
     while(!SSPSTAT.BF);
     SSPSTAT.BF = 0;
 
     inByte = SSPBUF;
     
     return inByte;
}
 
void main() {
 
     ADCON1 = 0x0F;
     CMCON = 0x07;
     CVRCON = 0x00;
 
     TRISA = 0xFF;
     TRISB = 0x01;
     TRISC = 0x00;
 
     PORTA = 0x00;
     PORTB = 0x00;
     PORTC = 0x00;
 
     SSPSTAT = 0x00;
     SSPCON1 = 0x22;
 
     while(1) {
 
          if(!PORTA.F3) {
               Delay_ms(50);
               if(!PORTA.F3) {
 
                    SPIInData = HW_SPI_Transfer(SPIOutData);
 
                    if(!PORTA.F0) {
                         Delay_ms(50);
                         if(!PORTA.F0) {
                                SPIInData <<= 2;
                                LATB = SPIInData;
                         }
                    }
 
                    if(!PORTA.F4) {
                         Delay_ms(50);
                         while(!PORTA.F4);
                         toggleValue = ~toggleValue;
                    }
 
                    if(!toggleValue)++SPIOutData;
                    else if(toggleValue)--SPIOutData;
 
                    Delay_ms(1000);
               }
          }
     }
}

 

Attachments

  • 18F2550 HW SPI.rar
    48.2 KB · Views: 91

I have implemented what you want in HW SPI C code and it is working fine. PORTB is used to display received SPI data. RB2-RB7 is used to output data and so you can't see 8 bit value on PORTB. SDO is connected to SDI. Code is written in mikroC PRO PIC. Just study the code and implement it in ASM.

Proteus simulation attached.

- - - Updated - - -


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
unsigned char SPIInData = 0, SPIOutData = 0;
char toggleValue = 0;
 
unsigned char HW_SPI_Transfer(unsigned char SPIData) {
     unsigned char inByte = 0;
 
     SSPBUF = SPIData;
     while(!SSPSTAT.BF);
     SSPSTAT.BF = 0;
 
     inByte = SSPBUF;
     
     return inByte;
}
 
void main() {
 
     ADCON1 = 0x0F;
     CMCON = 0x07;
     CVRCON = 0x00;
 
     TRISA = 0xFF;
     TRISB = 0x01;
     TRISC = 0x00;
 
     PORTA = 0x00;
     PORTB = 0x00;
     PORTC = 0x00;
 
     SSPSTAT = 0x00;
     SSPCON1 = 0x22;
 
     while(1) {
 
          if(!PORTA.F3) {
               Delay_ms(50);
               if(!PORTA.F3) {
 
                    SPIInData = HW_SPI_Transfer(SPIOutData);
 
                    if(!PORTA.F0) {
                         Delay_ms(50);
                         if(!PORTA.F0) {
                                SPIInData <<= 2;
                                LATB = SPIInData;
                         }
                    }
 
                    if(!PORTA.F4) {
                         Delay_ms(50);
                         while(!PORTA.F4);
                         toggleValue = ~toggleValue;
                    }
 
                    if(!toggleValue)++SPIOutData;
                    else if(toggleValue)--SPIOutData;
 
                    Delay_ms(1000);
               }
          }
     }
}


well, i have to say i am not clear about your code. I don't understand. Sorry for that.
But your sentences make sense. I figure out that you understand what i am doing.

I also try to write the code in C. But the result is still not what i expect.
 

You can see my Proteus simulation. I have used 4 MHz external clock. You can also test in hardware. As soon as data is placed in SSPBUF, data is sent out 1 bit at a time with MSB first. The same data is also read as ADO is connected to SDI. after 8 bit in SSPBUF is shifted out, 8 bits also fill SSPBUF from SDI. I am shifting it twice to left so that the data when written to PORTB doesn't affect the SCK and ADI lines.
 

You can see my Proteus simulation. I have used 4 MHz external clock. You can also test in hardware. As soon as data is placed in SSPBUF, data is sent out 1 bit at a time with MSB first. The same data is also read as ADO is connected to SDI. after 8 bit in SSPBUF is shifted out, 8 bits also fill SSPBUF from SDI. I am shifting it twice to left so that the data when written to PORTB doesn't affect the SCK and ADI lines.

I changed your code into
Code:
#include <xc.h>
void initChip();
//void interrupt ISPread();
unsigned char ISPsend(unsigned char);

void interrupt ISPread(){
     if(PIR1bits.SSPIF == 1)
       PIR1bits.SSPIF = 0;
        while(!SSPSTATbits.BF);
        SSPSTATbits.BF =0;
       LATB = SSPBUF;
       for(int i =0; i<1000;i++){}
}
void initChip(){
    PORTA = 0x00; //Initial PORTA
    PORTB = 0x00; //Initial PORTB
    PORTC = 0x00; //Initial PORTC

    TRISA = 0xff; //Define PORTA as input
    TRISB = 0x01; //Define PORTB as output
    TRISC = 0x00; //Define PORTC as output

    ADCON1 = 0x0f; //Turn off ADcon
    CMCON = 0x07; //Turn off Comparator

    SSPSTAT = 0x00;
    SSPCON1 = 0x22;

    PIE1bits.SSPIE = 1;
    INTCONbits.GIE = 1 ;
    INTCONbits.PEIE =1; // enable peripherial when priority is disabled
    RCONbits.IPEN =0  ; //disable priority

    OSCCON = 0x12; //125KHz
}

unsigned char ISPsend(unsigned char SPIData){

    unsigned char inByte = 0;
    SSPBUF = SPIData;
    while(!SSPSTATbits.BF);
    SSPSTATbits.BF=0;
    for(int i =0; i<1000;i++){} //delay
     inByte = SSPBUF;
    return inByte;
}

void main() {
    unsigned char counter = 0; // local 8 bit variable
    initChip(); // Initial all the PORTs and some configurations

    while(1) { // Endless loop : make sure the program runs continuously

        if (PORTAbits.RA0 == 1) //Check RA0, if it is equal to value 1
        {
            if (counter <255) // Up counter
                counter = counter + 1;
            else
                counter = 0;
        }
        else
        {
            if (counter > 0) // Down counter
                counter = counter -1;
            else
                counter = 255;
        }
       PORTB = ISPsend(counter)*4;
//        ISPsend(counter);
        for(int i =0; i<1000;i++){}
    } 
}

it is really not working
 

Please Zip and attach your latest XC8 project files. Did you test my .hex in hardware ?

Don't use delays inside ISR. Did you simulate my Proteus designs with my .hex files ?

Don't do this.

Code C - [expand]
1
LATB = SSPBUF;

RB0 is configured as input (SDI). You have to shift SSPBUF values 2 bits to left and then assign it to PORTB.
 

Please Zip and attach your latest XC8 project files. Did you test my .hex in hardware ?

Don't use delays inside ISR. Did you simulate my Proteus designs with my .hex files ?

Don't do this.

Code C - [expand]
1
LATB = SSPBUF;

RB0 is configured as input (SDI). You have to shift SSPBUF values 2 bits to left and then assign it to PORTB.

Hi, Thank you, milan.
I've got the correct answer now.
First i should not use interrupt.
Second, before send data, i should read the SSPBUF once in order to automatically set the SSPSTAT BF to zero.
I post here my code.

And i remember that i will not use delay in the ISR anymore.
I dont know what is proteus, i am sure i dont have this software.


But i still have questions. Haha, i am really a beginner.
First,
You have to shift SSPBUF values 2 bits to left and then assign it to PORTB.
do you mean that we only give values to RB2 to RB7? Because RB0 and RB1 is used in other function. Do i understand correctly?

Second. How should write delay? I mean how to accurately calculate the time delay? I found some webpages that discuss this issue, but i really dont know how they calculate.... do you have any tutorial for beginner?
 

Attachments

  • Lab3-1PIC-masterMode.X.zip
    36.8 KB · Views: 92
Last edited:

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top