Передача и прием 16-битного регистра данных Slave и 8-битного ведущего регистра AVR через связь SPI

Я новичок в программировании Avr, у меня есть ведомое устройство с 16-битным регистром (микросхема памяти), и я хочу читать и записывать в память через Atmega328 (8-битный регистр), я знаю, что мне нужно отправить 8 на 8 бит, Я уже пытался запрограммировать это, но я не мог читать с моего ведомого устройства с помощью отладчика Atmel Studio, может ли кто-нибудь посоветовать мне, пожалуйста?

Протокол связи с моим чипом - SPI.

Последовательная связь описана в техническом описании микросхемы как:

  1. ЧИТАТЬ :

Для чтения из чипа необходимо отправить:

0x03            = 0b00000011:          8 bit  READ command
0x0000 - 0x07FF = 0bXXXXXAAA AAAAAAAA: 16 bit ADDRESS (5 upper bits don't care)

Тогда я получу:

0x0000 - 0xFFFF = 0bDDDDDDDD DDDDDDDD: 16 bit DATA
  1. ЗАПИСЫВАТЬ :

Для записи на чип мне нужно отправить:

0x02            = 0b00000010:          8 bit  WRITE command
0x0000 - 0x07FF = 0bXXXXXAAA AAAAAAAA: 16 bit ADDRESS (5 upper bits don't care)
0x0000 - 0xFFFF = 0bDDDDDDDD DDDDDDDD: 16 bit DATA
  1. Схема памяти:

Область пользовательской памяти изменяется от 0x0000 до 0xA6F.

  1. Используйте регистр информации SPI:

В режиме последовательной связи, если LSI регистрирует ошибку при выполнении команды READ / WRITE, коды ошибок будут сохранены в регистре информации об ошибках SPI.

Bit       15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
Function  0  0  0  0  0  0  0  0  0  0  0  0  | ERROR* |
* :  ERROR
b1000 : Low voltage detection
b0100 : Write NG
b0010 : Read NG
b0001 : NG because RF occurred
b0000 : Finished successfully

Моя инициализация SPI:

void spi_init()
// Initialize pins for spi communication
{

    // set MOSI , select chip SS and SCK Output, all others are outputs
    DDR_SPI |= ((1<<DD_MOSI)|(1<<DD_SCK) );/*|(1<<DD_SS))*/
    // set MISO us input 

     //Enable SPI, Master, set clock rate
     SPCR = (1<<SPE|(1<<MSTR)| (1<<SPR0)|       // SPI Enable
    (0<<SPIE)|              // SPI Interrupt Enable
    (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
    (1<<MSTR)|              // Master/Slave select
    (0<<SPR1)|(1<<SPR0)|    // SPI Clock Rate
    (1<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
    (1<<CPHA));           // Clock Phase (0:leading / 1:trailing edge sampling)

    SPSR = (1<<SPI2X);              // Double Clock Rate

}

void SPI_MasterTransmit(uint16_t cdata){
    SPDR = cdata;  //start transmission 
    while(!(SPSR & (1<<SPIF)));  // wait for transmission complete
}
 uint16_t SPI_SlaveReceive(void){
     while(!(SPSR & (1<<SPIF)));  //wait for reception complete     
     return (SPDR);             //return Data Register
 }

Прочитано:

uint16_t read_SPI( uint16_t address){
    uint16_t datar; 
        Slave_select;   
    // charger les données inf au buffer 
        SPDR = uint16_t( address & 0xFF);
        //attente lors de la premiere transmission 
        while(!(SPSR & (1<<SPIF) ));
        // premier octet est reçu 
        datar = SPDR;

        // charger les données sup au buffer 
        SPDR = uint16_t ((address >> 8) & 0xFF);
        //attente de la seconde tr 
        while(!(SPSR & (1<<SPIF) ));
        // seceond octet est reçu 
        datar = datar | ((uint16_t) (SPDR) << 8);
       Slave_deselect;
        return datar; 

}

Написать

void write_SPI (uint16_t address, uint16_t data){
    Slave_select;
    SPDR= data; 
    while(!(SPSR & (1<<SPIF)));
    /*data = SPDR;*/ // erase SPDR register 
    Slave_deselect; 
}

person D.G    schedule 28.06.2017    source источник
comment
Вы смотрели с помощью прицела, что выходит из порта SPI? Можем ли мы увидеть ваш код инициализации и код, который вы используете для доступа к флеш-памяти? Нам нужно гораздо больше информации, чем эта.   -  person DiBosco    schedule 28.06.2017
comment
Нет, я просто посмотрел на отладчик   -  person D.G    schedule 28.06.2017
comment
@DiBosco я разместил свой Код как ответ на свой вопрос   -  person D.G    schedule 28.06.2017
comment
Сразу приходит в голову одна вещь: вы не разблокировали вспышку. Ознакомьтесь с таблицей данных, как это сделать. Кроме того, вам действительно нужно взглянуть на свои линии SPI с осциллографом, чтобы убедиться, что они делают то, что, по вашему мнению, они делают.   -  person DiBosco    schedule 28.06.2017


Ответы (1)


На самом деле вы никогда не отправляете команду, а только младшие 8 бит адреса.

Примерно на стороне ATmega расположение выводов должно выглядеть так:

PORT? = (1u << MISO) | (1u << MOSI) | (1u << SCK) | (1u << CS);
DDR? = (1u << MOSI) | (1u << CS) | (1u << SCK);
/* pull-up on MISO, init all others idle high/active low */

Тогда функция чтения выглядит примерно так:

uint16_t read_SPI( uint16_t address){
    uint16_t res;
    PORT? &= ~(1u << CS); /* assert #CS */
    SPDR = 0x03u; /* READ command */
    while(!(SPSR & (1<<SPIF) ));
    SPDR = (address >> 8) & 0xFFu; /* high-order address bits */
    while(!(SPSR & (1<<SPIF) ));
    SPDR = (address >> 0) & 0xFFu; /* low-order address bits */
    while(!(SPSR & (1<<SPIF) ));
    SPDR = 0xFFu; /* dummy write to clock in high-order data bits */
    while(!(SPSR & (1<<SPIF) ));
    res = SPDR;
    SPDR = 0xFFu; /* dummy write to clock in low-order data bits */
    res <<= 8;
    res = SPDR;
    PORT? |= (1u << CS); /* deassert #CS */
    return res;
}

Обратите внимание, что это очень простой пример, и обычно вы не хотите блокировать микроконтроллер на неопределенное время, ожидая флагов состояния SPI. Однако подумайте о том, чтобы довести этот код до такой степени, чтобы вы могли надежно читать и записывать в / из EEPROM. Затем вы можете добавить немного абстракции и использовать структуры данных и основанную на прерываниях процедуру SPI для обработки доступа к памяти.

person FRob    schedule 03.07.2017