PIC Vietnam

PIC Vietnam (http://www.picvietnam.com/forum/index.php)
-   dsPIC - Bộ điều khiển tín hiệu số 16-bit (http://www.picvietnam.com/forum/forumdisplay.php?f=29)
-   -   Thắc mắc về giao tiếp SPI (http://www.picvietnam.com/forum/showthread.php?t=4666)

trangham283 29-07-2009 09:26 AM

Thắc mắc về giao tiếp SPI
 
Xin chào mọi người,

Em đã có đọc qua tìm hiểu về giao tiếp SPI và em đang viết chương trình để thử đọc và viết vào EEPROM 25LC256 nhờ dsPIC30F2011. Em đã tham khảo tài liệu cũng như code mẫu của microchip, cụ thể là cái này:

http://www.microchip.com/stellent/id...pnote=en023868

đã thay đổi một số chỗ sao cho phù hợp với dsPIC của mình.

Hiện giờ em có thắc mắc về phần configuration cho thanh ghi SPI1CON của PIC, cụ thể là phần chọn Mode: word hay byte communication.

Trong tài liệu của EEPROM, theo em hiểu thì EEPROM sẽ chỉ nhận từng byte một, ("The 25LC256 contains an 8-bit instruction register), như vậy có phải em sẽ phải chọn chế độ giao tiếp byte?

Phần em không hiểu hiện giờ là: thanh đệm SPI1BUF của PIC dài 16 bit, khi viết dữ liệu cần chuyển đi cũng là viết 16 bit, như vậy khi giao tiếp theo chế độ 1 byte thì cái byte còn lại nó vứt đi đâu ạ?

namqn 29-07-2009 10:07 AM

Trích:

Nguyên văn bởi trangham283 (Post 28161)
Xin chào mọi người,

Em đã có đọc qua tìm hiểu về giao tiếp SPI và em đang viết chương trình để thử đọc và viết vào EEPROM 25LC256 nhờ dsPIC30F2011. Em đã tham khảo tài liệu cũng như code mẫu của microchip, cụ thể là cái này:

http://www.microchip.com/stellent/id...pnote=en023868

đã thay đổi một số chỗ sao cho phù hợp với dsPIC của mình.

Hiện giờ em có thắc mắc về phần configuration cho thanh ghi SPI1CON của PIC, cụ thể là phần chọn Mode: word hay byte communication.

Trong tài liệu của EEPROM, theo em hiểu thì EEPROM sẽ chỉ nhận từng byte một, ("The 25LC256 contains an 8-bit instruction register), như vậy có phải em sẽ phải chọn chế độ giao tiếp byte?

Phần em không hiểu hiện giờ là: thanh đệm SPI1BUF của PIC dài 16 bit, khi viết dữ liệu cần chuyển đi cũng là viết 16 bit, như vậy khi giao tiếp theo chế độ 1 byte thì cái byte còn lại nó vứt đi đâu ạ?

Mời bạn đọc tutorial sau:

http://www.picvietnam.com/forum/showthread.php?t=2481

Thông tin liên quan đến thắc mắc của bạn đã được đề cập trong tutorial đó.

Thân,

Serenade 29-07-2009 12:28 PM

Đương nhiên là cấu hình byte rùi bạn.

Code:

#define EE_SSPIF_BIT IFS2bits.SPI2IF
#define SPIREAD    0x03
#define SPIWRITE    0x02
#define SPIWRDI    0x04
#define SPIWREN    0x06
#define SPIRDSR    0x05
#define SPIWRSR    0x01

/*********************************************************************/
void EE_SPIPut(BYTE v)
{
  BYTE dummy;

  EE_SSPIF_BIT = 0;
  dummy = EE_SSPBUF_REG;
  EE_SSPBUF_REG = v;
  while(EE_SSPIF_BIT == 0 );
}
/*********************************************************************/
BYTE EE_SPIGet(void)
{
  EE_SPIPut(0x00);
  return EE_SSPBUF_REG;
}
/*********************************************************************/

BYTE NVMRead(DWORD address)// read a 16-bit value starting at an even address
{
        BYTE msb,lsb,temp;
       
        // wait until any work in progress is completed
        do
        {
                SPISelectEEPROM();
                EE_SPIPut(SPIRDSR);
                temp = EE_SPIGet();//read status register
                SPIUnselectEEPROM();
        }while(temp & 0x03);
       
        // perform a 16-bit read sequence (two byte sequential read)
        SPISelectEEPROM();                        // select the Serial EEPROM
        EE_SPIPut(SPIREAD);// read command
        EE_SPIPut(address >> 8);        // address MSB first
        EE_SPIPut(address & 0xff);// address LSB (word aligned)
        //msb = EE_SPIGet();
        lsb = EE_SPIGet();       
        SPIUnselectEEPROM();
        return (lsb);

}//ReadNVM
/*********************************************************************/
void NVMWrite( DWORD address, BYTE data)
{ // write a 16-bit value starting at an even address
        BYTE temp;
        // wait until any work in progress is completed
        do
        {
                SPISelectEEPROM();
                EE_SPIPut(SPIRDSR);
                temp = EE_SPIGet();//read status register
                SPIUnselectEEPROM();
        }while(temp & 0x03);
        // Set the Write Enable Latch
        SPISelectEEPROM();
        EE_SPIPut(SPIWREN);
        SPIUnselectEEPROM();
       
        // perform a 16-bit write sequence (2 byte page write)
        SPISelectEEPROM();                                        // select the Serial EEPROM
        EE_SPIPut(SPIWRITE);
        EE_SPIPut(address >> 8);                //address MSB first
        EE_SPIPut(address & 0xff);        // address LSB (word aligned)
        EE_SPIPut(data);
        SPIUnselectEEPROM();

}//WriteNVM


trangham283 29-07-2009 12:32 PM

Em cảm ơn anh Nam, ý anh là đoạn này ạ? Em có đọc qua tutorial này rồi, nhưng em vẫn không hiểu lắm :"> Anh có thể làm ơn giải thích thêm cho em về thao tác truyền dữ liệu sang slave được không ạ?

Trích:

Master có thể ghi dữ liệu mới vào bộ đệm SPI khi dữ liệu cũ đang được dịch ra. Khi
thanh ghi dịch trống thì dữ liệu mới sẽ được chuyển từ bộ đệm vào. Người dùng chỉ
cần chú ý kiểm tra bit SPITBF trong thanh ghi SPIxSTAT tương ứng để tránh ghi vào bộ
đệm khi nó đang chứa dữ liệu.

Cùng lúc với dữ liệu được dịch ra từ bộ đệm truyền, dữ liệu cũng được lấy vào
thanh ghi dịch, và khi bộ đệm nhận đã nhận đủ số bit cần thiết thì dữ liệu sẽ được
chuyển vào bộ đệm nhận
, và bit SPIIF sẽ được bật. Nếu ngắt SPI được cho phép, bằng cách bật bit SPIIE, thì một ngắt SPI sẽ được tạo ra. Bit SMP trong thanh ghi SPIxCON
cho phép chọn vị trí lấy mẫu dữ liệu vào, ở giữa hay cuối mỗi chu kỳ của bit.

Bit SPIRBF trong thanh ghi SPIxSTAT cho biết bộ đệm nhận có dữ liệu. Nếu dữ liệu
này không được đọc ra khi thanh ghi dịch hoàn tất thao tác dịch dữ liệu mới vào thì sẽ
xảy ra tràn bộ đệm nhận, với bit SPIROV trong thanh ghi SPIxSTAT được bật. Khi đó
dữ liệu mới sẽ không được chuyển vào bộ đệm và bị mất
.
Có nghĩa là nếu em config giao tiếp 8-bit, sau khi SPIxSR nhận 8 bit, 8 bit này sẽ được chép vào SPIxRXB rồi sẽ cần được đọc ra để tránh tràn và mất dũ liệu?

Em xin lỗi nếu em lại đọc sót phần quan trọng :P, nhưng em vẫn không hiểu thao tác truyền dữ liệu. Đoạn trên là nhân dữ liệu từ slave, vậy nếu em muốn gửi dữ liệu, em cần viết vào SPIxBUF, thì vẫn là viết 16 bit phải không ạ? Hay là em phải dùng lệnh mov.b? (Em đang tập viết bằng hợp ngữ)

Em cảm ơn anh nhiều ạ.

trangham283 29-07-2009 12:42 PM

Cảm ơn bạn Serenade, rất tiếc mình đang viết chương trình bằng hợp ngữ, mình lại chưa lập trình bằng C bao giờ cả nên code bạn viết mình không hiểu lắm.

Dù sao cũng rất cảm ơn bạn!

Serenade 29-07-2009 12:49 PM

Bắt đầu viết bằng hợp ngữ thì tốt,nhưng mình khuyên là sau này nên chuyển qua C vì những chương trình lớn viết bằng hợp ngữ không nổi đâu.

Serenade 29-07-2009 12:59 PM

Mình sẽ nói sơ về giao tiếp spi nhé.Giao tiếp spi sử dụng chung bộ đệm truyền nhận dữ liệu,một đầu dữ liệu đẩy ra ngoài thì đồng thời đầu còn lại của bộ đệm được đưa dữ liệu vào.do đó bạn muốn nhận dữ liệu từ slave (eeprom) thì phải gửi một byte bất kỳ,còn muốn truyền dữ liệu đi thì trước hết phải đọc 1 byte dump trong vùng đệm trước khi truyền để tránh trường hợp tràn vùng đệm nhận vì bạn truyền 1 byte đi đồng nghĩ với việc bạn nhận một byte từ slave.

namqn 29-07-2009 05:51 PM

Trích:

Nguyên văn bởi trangham283 (Post 28171)
Em cảm ơn anh Nam, ý anh là đoạn này ạ? Em có đọc qua tutorial này rồi, nhưng em vẫn không hiểu lắm :"> Anh có thể làm ơn giải thích thêm cho em về thao tác truyền dữ liệu sang slave được không ạ?

Có nghĩa là nếu em config giao tiếp 8-bit, sau khi SPIxSR nhận 8 bit, 8 bit này sẽ được chép vào SPIxRXB rồi sẽ cần được đọc ra để tránh tràn và mất dũ liệu?

Em xin lỗi nếu em lại đọc sót phần quan trọng :P, nhưng em vẫn không hiểu thao tác truyền dữ liệu. Đoạn trên là nhân dữ liệu từ slave, vậy nếu em muốn gửi dữ liệu, em cần viết vào SPIxBUF, thì vẫn là viết 16 bit phải không ạ? Hay là em phải dùng lệnh mov.b? (Em đang tập viết bằng hợp ngữ)

Em cảm ơn anh nhiều ạ.

Ngay dưới đoạn mà bạn vừa đưa lên là thông tin chọn cấu hình, nếu đặt bit MODE16 = 0 thì bạn sẽ dùng chế độ truyền thông 8-bit. Trong chế độ này, chỉ có 8 bit được dịch ra chân SDO, và 8 bit được dịch vào chân SDI.

Bạn ghi bao nhiêu bit vào SPIxBUF thì cũng chỉ có 8 bit thấp nhất được gửi sang slave khi chọn MODE16 = 0, và cũng chỉ có 8 bit thấp nhất là dữ liệu thực sự nhận được từ slave trong trường hợp này. Không nhất thiết phải dùng lệnh mov.b để lọc 8 bit dữ liệu nhận được từ slave, nhưng đó là một cách tốt.

Thân,

trangham283 30-07-2009 02:26 AM

Cảm ơn mọi người đã giúp mình trả lời những câu hỏi trên. Hic hic đây là code mình viết, mình dùng UART để kiểm tra xem việc đọc/viết dữ liệu nhưng vẫn không thành công.

Mình trước đó đã có một code riêng để kiểm tra UART, nên mình khá chắc chắn vấn đề nằm ở cái SPI này...

Các cao thủ có thể nhìn qua code này rồi giúp em được không ạ? Cảm ơn mọi người nhiều nhiều!


Code:

;Instruction shortcuts:
.equ        RDINS,3
.equ        WRINS,2
.equ        WRDI,4
.equ        WREN,6
.equ        RDSR,5
.equ        WRSR,1


ADDR:                .space 2                                ;Current Memory address
TOSEND:                .space 2
NUM:                .space 2

RDATA:                .space 2
OUTWORD:        .space 2




call        _spi_init

mov                #0xFFFF,W0
mov                W0,NUM

;WREN:
call        cslow
mov                #WREN,W0
mov                W0,OUTWORD
call        output
call        cshigh

call        cslow
mov                #WRINS,W0
mov                W0,OUTWORD
call        output

;Write address:
mov                ADDR,W0                                ;MSB of address
swap        W0
mov                W0,OUTWORD
call        output

mov                ADDR,W0                                ;LSB of address
mov                W0,OUTWORD
call        output

;Write data
mov        NUM,W0                                ;This would write only LSB
mov                W0,OUTWORD
call        output
call        cshigh


;Polling:
poll:
call        cslow
mov                #RDSR,W0
mov                W0,OUTWORD
call        output
mov                #0x0000,W0                        ;Dummy send to read
mov                W0,OUTWORD
call        output
mov                RDATA,W0
and                #0x0001,W0                        ;Is WIP bit clear?
bra                nz,poll
call        cshigh

send:
clr                ADDR

memrd1:

call        cslow
mov                #RDINS,W0
mov                W0,OUTWORD
call        output

;Write address:
mov                ADDR,W0                                ;address MSB
swap        W0
mov                W0,OUTWORD
call        output

mov                ADDR,W0                                ;address LSB
mov                W0,OUTWORD
call        output

mov                #0x00,W0                        ;Dummy write to retain clock
mov                W0,OUTWORD       
call        output
call        cshigh

mov                RDATA,W0
mov                W0,TOSEND

;Send to PC via UART

call        chktr       
mov                TOSEND,W0
mov                W0,U1TXREG
swap                W0
call                chktr
mov                W0,U1TXREG

done:
bra                done
;..............................................................................
;Subroutine: SPI Initialization
;..............................................................................
_spi_init:
mov                #0x013E,W0                        ;SS not used anyway
                                                        ;SDO pin controlled by module
                                ;Communication byte-wide
                                ;Input sampled at middle of data output line
                                ;CKE = 1: Output data changes on transition from CLK active to idle
                                ;CKP = 0: Idle state for CLK at low level
                                ;Master enable, scale: fsck = fcy/4        = 1MHz

mov                W0,SPI1CON
bclr        SPI1STAT,#SPIROV
bset        SPI1STAT,#SPIEN
clr                ADDR                                                ;Set first memory address to write to: 0x0000
return

;Sending instructions to EEPROM
output:
mov                OUTWORD,W8
mov                W8,SPI1BUF

chktrans:                                                        ;Is transmit buffer empty??
mov                SPI1STAT,W2
and                #0x0002,W2
bra                nz,chktrans

chkrd:
mov                SPI1STAT,W2
and                #0x0001,W2                                        ;Is receive buffer full?
bra                z,chkrd


mov                SPI1BUF,W8                                        ;Dump received data
mov                W8,RDATA
bclr        SPI1STAT,#SPIROV

return

cslow:
bclr        PORTB,#RB2
return

cshigh:
bset        PORTB,#RB2
return

chktr:
;Check if UART transmit buffer is full
mov                U1STA,W2
and                #0x0200,W2
bra                nz,chktr
return


trangham283 30-07-2009 05:21 AM

Update:

Hôm nay em đã kiểm tra mạch bằng máy đo dao động. Em cho hiện 4 kênh: SCK, CS, SDO và SDI.

Các kênh SCK, CS và SDO của PIC hoạt động đúng như em dự định, em có thấy các lệnh viết, đọc được dịch ra chân SDO một cách hợp lý. Tuy nhiên riêng kênh SDI thì luôn luôn 0. Điều này làm em nghĩ vấn đề nằm ở đoạn nhận lại dữ liệu từ EEPROM...

Mọi người có thể đọc qua code post ở phía trên của em rồi góp ý được không ạ?

Cảm ơn mọi người nhiều nhiều!

namqn 30-07-2009 09:35 AM

Trích:

Nguyên văn bởi trangham283 (Post 28211)
Update:

Hôm nay em đã kiểm tra mạch bằng máy đo dao động. Em cho hiện 4 kênh: SCK, CS, SDO và SDI.

Các kênh SCK, CS và SDO của PIC hoạt động đúng như em dự định, em có thấy các lệnh viết, đọc được dịch ra chân SDO một cách hợp lý. Tuy nhiên riêng kênh SDI thì luôn luôn 0. Điều này làm em nghĩ vấn đề nằm ở đoạn nhận lại dữ liệu từ EEPROM...

Mọi người có thể đọc qua code post ở phía trên của em rồi góp ý được không ạ?

Cảm ơn mọi người nhiều nhiều!

Bạn kiểm tra lại phần cứng xem có lỗi hay không. Nếu không có lỗi phần cứng thì bạn kiểm tra lại timing của các tín hiệu để xem EEPROM có làm việc được ở tốc độ đó hay không.

Thân,


Múi giờ GMT. Hiện tại là 05:05 PM.

Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam