Работа с SPI напрямую (решено)

Тема в разделе "Arduino & Shields", создана пользователем timon, 4 фев 2019.

Метки:
  1. timon

    timon Гик

    Уважаемые гуру, я тут попробовал с SPI поработать и не очень понимаю до чего доработался. Пожалуйста, кто что то подобное делал (без ардуиновской SPI.h) - посмотрите трезвым взглядом, нигде ли я не накосячил?

    Задача простая:
    1. передать команду 0х02 (запись в память)
    2. передать 24бита адреса (0х05)
    3. передать байт, который пишу в память (128)

    Затем
    1. передать команду 0х03 (чтение из памяти)
    2. передать 24бита адреса откуда читаем (0х05)
    3. обменяться байтом по SPI и вернуть его в функции

    Затем
    Сравнить принятый байт с 128 и если он 128 то мигать светодиодом "1010101010..." а если нет то "100000000100000000"

    В итоге то у меня сравнение проходит, странным образом это сравнение последнего значения в SPDR и если, к примеру, записать 255 по адресу 0005 а затем 128 по адресу 0006, то сравнение с адреса 0005 с 255 уже не проходит...

    Мучаю я вот эту микросхемку: https://datasheet.lcsc.com/szlcsc/Microchip-Tech-23LC1024-I-SN_C48388.pdf где черным по белому сказано:
    2019-02-04_11-10-44.png

    Код
    Код (C++):
    #include <avr/io.h>

    #define SPI_PORTX PORTB
    #define SPI_DDRX DDRB

    #define SPI_MISO 3
    #define SPI_MOSI 2
    #define SPI_SCK 1
    #define SPI_RAM 5
    #define SPI_FLASH 4

    void SPI_Init(void){
        SPI_DDRX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (0<<SPI_MISO);
        SPI_PORTX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (1<<SPI_MISO);
        SPCR = (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | (1<<SPR1) | (0<<SPR0);
        SPSR = (0<<SPI2X);
    }

    void RAM_WriteByte(uint32_t address, uint8_t data){
        SPI_PORTX &= ~(1<<SPI_RAM);

        SPDR = 0x02; //03 - for read
        while(!(SPSR & (1<<SPIF)));

        SPDR = address>>24;
        while(!(SPSR & (1<<SPIF)));
        SPDR = address>>16;
        while(!(SPSR & (1<<SPIF)));
        SPDR = address>>8;
        while(!(SPSR & (1<<SPIF)));

        SPDR = data;
        while(!(SPSR & (1<<SPIF)));

        SPI_PORTX |= (1<<SPI_RAM);
    }

    uint8_t RAM_ReadByte(uint32_t address){
        uint8_t report = 0;

        SPI_PORTX &= ~(1<<SPI_RAM);
        SPDR = 0x03;
        while(!(SPSR & (1<<SPIF)));

        SPDR = address>>24;
        while(!(SPSR & (1<<SPIF)));
        SPDR = address>>16;
        while(!(SPSR & (1<<SPIF)));
        SPDR = address>>8;
        while(!(SPSR & (1<<SPIF)));

        SPDR = report;
        while(!(SPSR & (1<<SPIF)));
        report = SPDR;

        SPI_PORTX |= (1<<SPI_RAM);

        return report;
    }


    void Delay(volatile int n){
        for(volatile int m=n;m;--m);
    }

    void LED_HIGH(){
        PORTC |= (1<<7);  //BUILTIN LED ON
    }

    void LED_LOW(){
        PORTC &= ~(1<<7);  //BUILTIN LED OFF
    }

    int main(void)
    {
        SPI_Init();
        DDRC = 255;
        uint8_t bbb = 0;
        uint32_t addr = 5;

        while (1)
        {
        RAM_WriteByte(addr,128);

        bbb = RAM_ReadByte(5);
        if (bbb == 128){
            LED_HIGH();
            Delay(65000);
            LED_LOW();
            Delay(65000);
        } else {
            LED_HIGH();
            Delay(65000);
            LED_LOW();
            Delay(65000);
            Delay(65000);
            Delay(65000);
            Delay(65000);
            Delay(65000);
            Delay(65000);
            Delay(65000);
            Delay(65000);
            Delay(65000);
            Delay(65000);
        }

        }
    }
     
    Последнее редактирование: 4 фев 2019
  2. parovoZZ

    parovoZZ Гуру

    NikitOS и timon нравится это.
  3. timon

    timon Гик

    Спасибо )
    Вопрос есть, вы пишете, что
    У меня пин SS сконфигурирован на выход (PORTB, пятый бит) - (1<<SPI_RAM):
    Код (C++):
    SPI_DDRX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (0<<SPI_MISO);
    я и работаю с чипом памяти как мастер, но для работы мне необходимо 5-й бит PORTB переводить в низкий уровень, что бы заселектить чип памяти как он того требует. Возможно ли что аппаратный SPI в микроконтроллере бросает всё и переключает себя в режим SLAVE?
     
  4. parovoZZ

    parovoZZ Гуру

    В качестве пина SS для режима мастер может быть задействован абсолютно любой пин. Но аппаратный пин SS обязательно должен быть сконфигурирован на выход. Можно и на вход, но тогда его подтянуть к плюсу. Если SPI используется как Slave, то пином SS управляется работа SPI - низкий уровень - SPI слушает и записывает биты с линии MOSI. Когда SPI мастер и пин SS используется как вход, то при появлении низкого уровня SPI сразу же (закончена передача текущего байта или нет - ему пофигу) переключает себя в SLAVE. На бракованных кристаллах слышал историю, что низкий уровень на выводе SS также переключает SPI в SLAVE режим. Проверить просто - на линии SCK в SLAVE режиме нет тактирования при попытке передать байт.
     
    arkadyf и timon нравится это.
  5. timon

    timon Гик

    Так оно и есть ) Использую PB5 как SS для RAM.

    Я про это читал, но не придал особого значения )))
    Получается, что
    2019-02-04_11-50-46.png
    надо еще
    Код (C++):
    // это добавить
    #define SPI_SS 0
    // и тут проинитить на выход
    SPI_DDRX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_SS) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (0<<SPI_MISO);
    // и поднять
    SPI_PORTX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_SS) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (1<<SPI_MISO);
    Спасибо огромное, вечером попробую ))
     
    Последнее редактирование: 4 фев 2019
  6. timon

    timon Гик

    Заработало!!! Теперь у меня в ардуинке есть 128кб памяти, на все хватит! Сам спаял, сам дровишку написал )) Спасибо за науку!

    Что было:
    помимо забытого SS я там еще жесточайшим образом с преобразованием адреса с 32bit в 24bit накололся, поэтому запись/чтение всегда шли по нулевому адресу, вызывая столь необычный баг, когда проверку проходит только последнее записанное значение.
     
    Daniil нравится это.