Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
 
0 / 0 / 1
Регистрация: 05.04.2017
Сообщений: 59
1

передача и приём данных по SPI на STM32

16.07.2020, 19:15. Просмотров 304. Ответов 11
Метки нет (Все метки)

Здравствуйте, уважаемые форумчане.
Пытаюсь наладить общение STM32f723IE, что на плате DISCOVERY и STM32F407VG на дешевой китайской отладке.
Все это дело настраиваю на CMSIS и оба процессора в режиме мастера на отправку сообщений успешно настроились и данные посылают. Пытаюсь пока настроить F4 как slave, F7 как мастер. Пока что без прерываний и ПДП, это все потом.

Вот настройка STMF723
C
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
void Spi2GpioInit(void)
{
    /********SPI2 GPIO Configuration*********/
    // PI1   ------> SPI2_SCK
    // PC2   ------> SPI2_MISO
    // PC3   ------> SPI2_MOSI
    // PI0   ------> SPI2_CS
    RCC->AHB1ENR|= RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIOIEN;                   // GPIOA and  GPIOBclock enable
    tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIOIEN);
 
    GPIOI-> MODER |= GPIO_MODER_MODER1_1;                                       // PI1 AF mode
    GPIOI-> AFR[0] |= GPIO_AFRL_AFRL1_0 | GPIO_AFRL_AFRL1_2;                    // AF5 function PI1
    GPIOI->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR1;
    GPIOC-> MODER |= GPIO_MODER_MODER2_1 | GPIO_MODER_MODER3_1;                 // PC2, PC3 AF mode
    GPIOC-> AFR[0] |= GPIO_AFRL_AFRL2_0 | GPIO_AFRL_AFRL2_2;                    // AF5 function PC2
    GPIOC-> AFR[0] |= GPIO_AFRL_AFRL3_0 | GPIO_AFRL_AFRL3_2;                    // AF5 function PC3
    GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR2 | GPIO_OSPEEDER_OSPEEDR3;          // Very high speed
 
    GPIOI-> MODER |= GPIO_MODER_MODER0_0;                                       // PI0 output mode
    GPIOI->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR0;                                   // Very high speed
}
 
void Spi2Init_8BitData(void)
{
    /***************SPI2 configuration*************/
    // master mode
    // frequency = 6.75 MHz
    // data size = 8 bit
 
    RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;                                         // SPI2 clock enable
    tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_SPI2EN);
 
    SPI2->CR1 |= SPI_CR1_MSTR | SPI_CR1_SSI;                                    // Master configuration
    //SPI1->CR1 &= ~SPI_CR1_CPOL;                                               // Clock to 0 when idle
    //SPI1->CR1 &= ~SPI_CR1_CPHA;                                               // First clock transition is the first data capture edge
    SPI2->CR1 |= SPI_CR1_SSM;                                                   // NSS managed internally. NSS pin not used and free
    SPI2->CR1 &= ~SPI_CR1_BR;
    SPI2->CR1 |= SPI_CR1_BR_1;                                                  // BaudRate control equal to fPCLK/8
    //SPI1->CR1 &= ~SPI_CR1_LSBFIRST;                                           // Data is transmitted with the MSB first
    //SPI1->CR1 &= ~SPI_CR1_CRCEN;                                              // CRC calculation disabled
    SPI2->CR2 |= SPI_CR2_DS;
    SPI2->CR2 &= ~SPI_CR2_DS_3;                                                 // Data size = 8 bit
 
    SPI2-> CR2 |= SPI_CR2_RXNEIE;
 
    Spi2Enable;
    Spi2GpioInit();                                                             // Enable Gpio for SPI2
}
Функция отправки байта
C
1
2
3
4
5
6
7
8
/********** Send 1 byte to SPI ************/
void WriteByteToSpi(SPI_TypeDef *spi, uint8_t TxData)
{
    while(!(spi -> SR & SPI_SR_TXE));
    *(uint8_t*)&spi -> DR = TxData;
    while(!(spi -> SR & SPI_SR_TXE));
        while(spi -> SR & SPI_SR_BSY);
}

Это настройка STM32F407

C
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
void Spi2_Slave_GpioInit(void)
{
    /********SPI2 Slave mode GPIO Configuration*********/
    // PB13   ------> SPI2_SCK
    // PB15   ------> SPI2_MOSI
    // PB14   ------> SPI2_MISO
    // PB12   ------> SPI2_CS
 
    RCC->AHB1ENR|= RCC_AHB1ENR_GPIOBEN;                                 // GPIOB clock enable
    tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOBEN);
    GPIOB-> MODER |= GPIO_MODER_MODER12_1 | GPIO_MODER_MODER13_1 |
            GPIO_MODER_MODER14_1 | GPIO_MODER_MODER15_1;                // PB12, PB13, PB14, PB15 AF mode
    GPIOB-> AFR[1] |= GPIO_AFRH_AFSEL12_0 | GPIO_AFRH_AFSEL12_2;        // AF5 function PP12
    GPIOB-> AFR[1] |= GPIO_AFRH_AFSEL13_0 | GPIO_AFRH_AFSEL13_2;        // AF5 function PP13
    GPIOB-> AFR[1] |= GPIO_AFRH_AFSEL14_0 | GPIO_AFRH_AFSEL14_2;        // AF5 function PP14
    GPIOB-> AFR[1] |= GPIO_AFRH_AFSEL15_0 | GPIO_AFRH_AFSEL15_2;        // AF5 function PP1
    GPIOB-> OSPEEDR |= GPIO_OSPEEDER_OSPEEDR12 | GPIO_OSPEEDER_OSPEEDR13
            | GPIO_OSPEEDER_OSPEEDR14 | GPIO_OSPEEDER_OSPEEDR15;        // Very high speed
}
 
void Spi2_Slave_Init_8BitData(void)
{
    /***************SPI2 configuration*************/
    // slave mode
    // data size = 8 bit
 
    RCC->APB1ENR|=RCC_APB1ENR_SPI2EN;                                   // SPI2 clock enable
    tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_SPI2EN);
 
    SPI2->CR1 |= SPI_CR1_BIDIOE;
    SPI2->CR1 &= ~SPI_CR1_DFF;                                          // Data length for SPI transfer:  8 bits
    SPI2->CR1 &= ~SPI_CR1_CPOL;                                         // Clock to 0 when idle
    SPI2->CR1 &= ~SPI_CR1_CPHA;                                         // First clock transition is the first data capture edge
    SPI2->CR1 &= ~SPI_CR1_SSM;                                          // Software slave management disabled. Hardware NSS pin
    SPI2->CR2 &= ~SPI_CR2_FRF;                                          // Motorola mode. Used as default value
    SPI2->CR1 &= ~SPI_CR1_MSTR;                                         // Slave configuration
 
    Spi2Enable;
    Spi2_GpioInit();
}
Ну и в основном цикле на слейве жду принятых данных и отправляю обратно на мастер
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
while(1)
    {
        while(!(SPI2->SR & SPI_SR_RXNE));
        RxBuf[0] = SPI2 -> DR;
        TxBuf[0] = RxBuf[0];
        //WriteByteToSpi(SPI2, 0x99);
 
        while(!(SPI2 -> SR & SPI_SR_TXE));
        *(uint8_t*)&SPI2 -> DR = TxBuf[0];
        //while(!(SPI2 -> SR & SPI_SR_TXE));
 
        while(SPI2 -> SR & SPI_SR_BSY);
        GPIOA -> BSRR |= GPIO_BSRR_BR1;
    }

На мастере сначала отправляю данные, потом жду ответ

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while(1)
    {
        if(GPIOA -> IDR & GPIO_IDR_ID0)
        {
            Spi2CsON;
            WriteByteToSpi(SPI2, 0x81);
            while(SPI2 -> SR & SPI_SR_BSY);
            
            while(!(SPI2->SR & SPI_SR_RXNE));
            RxBuf[0] = SPI2 -> DR;
            if(RxBuf[0] == 0x99)
            {
                GPIOA -> BSRR |= GPIO_BSRR_BS7;
            }
            
            Spi2CsOF;
        }
    }
так вот зависает при ожидании ответа от слейва на строчке while(!(SPI2->SR & SPI_SR_RXNE));
То есть не выставляется бит RXNE, хотя слейв данные отправил.

Подскажите пожалуйста что я делаю не так.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
16.07.2020, 19:15
Ответы с готовыми решениями:

SPI: прием и передача
Добрый день. Осваиваю SPI на контроллере Atmega168 (slave). master устройство - Raspberry pi. Прием...

ADS16xx прием данных по SPI
Приветствую Работаю с АЦП из этой серии, конкретно с ADS1672 на stm32f407. Принимаю по SPI в...

Извлечение данных по SPI STM32
Здравствуйте, осваиваю SPI на STM32. Не получается организовать извлечение данных. Использую...

Передача данных по SPI на расстояние
Здравствуйте. Почти уже доделал проект, где 2 МК (ATm16 и 8) общаются друг с другом по SPI, убив...

11
103 / 76 / 14
Регистрация: 15.11.2012
Сообщений: 523
20.07.2020, 01:04 2
Попробуйте вместо
C++
1
RxDuf[0] = SPI2 -> DR
Написать
C++
1
RxDuf[0] = *(volatile uint8_t *)(0x40015000 + 0x0C);
где вместо 0x40015000 надо вписать базовый адрес используемого вами SPI.
Заметил, что при использовании обращения вида SPI2 -> DR он то ли выдает по два байта сразу (регистр 16-разрядный), то ли еще чего, но ничего не работает нормально независимо от типа (размера) lvalue.
0
Почетный модератор
11086 / 4058 / 388
Регистрация: 12.06.2008
Сообщений: 11,775
20.07.2020, 11:48 3
alexey6689, если RxDuf - это массив из uint8_t, то в этих двух записях нет практической разницы. В обоих случаях будут использоваться только младшие 8 бит, прочитанных из регистра, и в обоих случаях регистр будет считаться прочитанным. Кроме того, в даташите явно сказано, что когда SPI настроен на 8-битный режим, то и в регистре используются только младшие 8 бит, а старшие всегда будут читаться нулями.
0
811 / 493 / 160
Регистрация: 30.07.2015
Сообщений: 1,623
20.07.2020, 11:56 4
Dim_Dimich,
Чтобы из слейва что-то вышло надо из него эти данные "вытолкнуть". Так как данные передаются по клоку на линии SCK мастеру надо дать туда этот клок, ибо слейв сам это делать не умеет. Соответственно нам надо в линию MOSI дать Dummy байт.
Что то подобное:
C
1
2
3
4
5
  
        SPI2 -> DR = 0xFF;
        while(!(SPI2->SR & SPI_SR_RXNE));
        RxBuf[0] = SPI2 -> DR;
        TxBuf[0] = RxBuf[0];
0
103 / 76 / 14
Регистрация: 15.11.2012
Сообщений: 523
20.07.2020, 16:18 5
Цитата Сообщение от Humanoid Посмотреть сообщение
если RxDuf - это массив из uint8_t,
Это все понятно и так и меня тоже так было.
Однако проблемы с чтением SPI у меня были решены именно тем путем что я описал. И да, у меня тоже было указано 8 бит, и переменные были те же... Или это баг периферии, или еще что-то. Но при каждом чтении регистра DR (размер слова в SPI был установлен 8-битным) я принимал байты через один, второй терялся.
Это не сложно сделать. Попробуйте.

Добавлено через 6 минут
Обращаю внимание, что регистр SPIx->DR в файле описания устройства (stm32f723xx.h) объявлен как uint32_t.
Поэтому тот факт, что вы это значение потом помещаете в 8-битную переменную ничего не даст - читается он все равно как 32-битный, с последующим усечением для "влезания" в 8 бит.
Скорее всего в этом все дело. В HAL для чтения используется явное приведение к 8-битному -
tmpreg = *((__IO uint8_t *)&hspi->Instance->DR);
0
Почетный модератор
11086 / 4058 / 388
Регистрация: 12.06.2008
Сообщений: 11,775
20.07.2020, 17:18 6
Цитата Сообщение от alexey6689 Посмотреть сообщение
в файле описания устройства (stm32f723xx.h) объявлен как uint32_t.
Без приставки __IO ? Тогда в этом может быть проблема. __IO (он же volatile) указывают компилятору, что работу с переменной нельзя как-либо оптимизировать. Без этого компилятор имеет право несколько раз прочитать переменную или не читать её вовсе. У меня сейчас нет под рукой библиотек для F7, поэтому не могу посмотреть... да и это могли исправить в современных версиях.

Цитата Сообщение от alexey6689 Посмотреть сообщение
Поэтому тот факт, что вы это значение потом помещаете в 8-битную переменную ничего не даст - читается он все равно как 32-битный, с последующим усечением для "влезания" в 8 бит.
Да, физически разница есть и в теории контроллер может понять, сколько бит запрашивает шина. Но я очень сильно сомневаюсь, что в контроллер SPI добавляли такой функционал, при котором он будет себя по-разному вести при запросе 8 бит или 32 бит. Да и это было бы явно описано в даташите. Более вероятно, что вы где-то ещё раз обращались к этому регистру. Возможно читали его, что бы какой-то бит в данных изменить или что-нибудь в этом роде. Либо, как я написал выше, такое могло произойти, если переменная в структуре описана без volatile (или __IO).
0
103 / 76 / 14
Регистрация: 15.11.2012
Сообщений: 523
20.07.2020, 18:11 7
Мне это все напоминает афоризм "кто хочет - ищет способ, кто не хочет - ищет причину".
Дело ваше.

На всякий случай почитайте раздел Reference guide - SPI - SPI functional description - Data transmission and reception procedures. В числе других там есть фраза "The read access must be always aligned with the RXFIFO
threshold configured by the FRXTH bit in SPIx_CR2 register". В вашей настройке FRXTH - нулевой, что означает, что RXNE выставляется только тогда, когда "0: RXNE event is generated if the FIFO level is greater than or equal to 1/2 (16-bit)". Только уже поэтому все может не работать. И читать в вашем случае надо с приведением к uint16_t, сразу по два байта.

Цитата Сообщение от Humanoid Посмотреть сообщение
Без приставки __IO
И да, приставка __IO там конечно есть. Я хотел указать на тот факт, что в HAL используется приведение типа к uint8_t, поэтому эту часть я опустил.

Добавлено через 3 минуты
Цитата Сообщение от Humanoid Посмотреть сообщение
и в теории контроллер может понять
Контроллер ничего не может понять, он не телепат. Если ассемблерная команда читает DWORD - будет чтение именно DWORD. Что там дальше - уже не важно. Кроме того, ядро и его внутренняя периферия (например контроллер SPI) связаны не больше, чем скажем контроллер (как микросхема) и например внешняя микросхема памяти. Поэтому даже если ядро что-то и "поймет" - периферия об этом все равно не узнает.
Цитата Сообщение от Humanoid Посмотреть сообщение
что в контроллер SPI добавляли такой функционал, при котором он будет себя по-разному вести при запросе 8 бит или 32 бит
Вот ровно про это я и написал выше - "The read access must be always aligned with the RXFIFO
threshold configured by the FRXTH bit in SPIx_CR2 register"
0
811 / 493 / 160
Регистрация: 30.07.2015
Сообщений: 1,623
20.07.2020, 21:47 8
alexey6689,
Цитата Сообщение от alexey6689 Посмотреть сообщение
Вот ровно про это я и написал выше - "The read access must be always aligned with the RXFIFO
threshold configured by the FRXTH bit in SPIx_CR2 register"
Вставал на эти грабли разок, правда есть одно но. Такая проблема с явным доступом возникала только в тех семействах где в SPI есть FIFO. Я лично столкнулся с F0 и F3. Не обратил внимание в RM, потом долго дебажил. В F1/F4 в SPI нет FIFO. собственно как и этой приписки в описании регистра DR, поэтому я таких граблей там не было.
0
103 / 76 / 14
Регистрация: 15.11.2012
Сообщений: 523
20.07.2020, 23:46 9
Однако в шапке говорится о том, что висит в ожидании данных как раз STM32F723:

Цитата Сообщение от Dim_Dimich Посмотреть сообщение
На мастере сначала отправляю данные, потом жду ответ

...

так вот зависает при ожидании ответа от слейва на строчке while(!(SPI2->SR & SPI_SR_RXNE));
То есть не выставляется бит RXNE, хотя слейв данные отправил.
0
Почетный модератор
11086 / 4058 / 388
Регистрация: 12.06.2008
Сообщений: 11,775
20.07.2020, 23:52 10
Цитата Сообщение от alexey6689 Посмотреть сообщение
Контроллер ничего не может понять, он не телепат.
Для этого не нужно быть телепатом. Хотя, шины (AHB и APB) 32-битные, но у них есть сигнал, который указывает, сколько байт из этих 32-бит являются полезными. Поэтому, если процессор передаёт именно 1 байт, то это будет именно 1 байт. На сколько я помню, с запросом на чтение всё так же - если процессор запрашивает 1 байт (через инструкцию ldrb), то переферия может это понять и прочитать только один байт. Но это актуально для работы с памятью, а с регистрами нет никакого смысла так извращаться, потому что они изначально 32-битные. И делать разное поведение при чтении 8 бит или 32 бит из одного регистра - это было бы очень странным.
0
103 / 76 / 14
Регистрация: 15.11.2012
Сообщений: 523
21.07.2020, 02:22 11
То есть даже то для вас не аргумент, что про разное поведение при чтении (как и при записи) 8 бит или 16 бит из регистра прямо написано в даташите...
Продолжайте в том же духе.
0
Почетный модератор
11086 / 4058 / 388
Регистрация: 12.06.2008
Сообщений: 11,775
21.07.2020, 11:22 12
Цитата Сообщение от alexey6689 Посмотреть сообщение
То есть даже то для вас не аргумент, что про разное поведение при чтении (как и при записи) 8 бит или 16 бит из регистра прямо написано в даташите...
На какой чип. Смотрел для 407 - там нет такой фразы.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.07.2020, 11:22

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Передача данных, вопросы по SPI и SSI интерфейсам
Привет всем. Я работаю над собственным электроприводом, обзавелся силовым драйвером для шагового...

Передача данных по SPI, между АЦП и микроконтроллером
Добрый день. Понемногу разбираясь с микроконтроллерами, решил связать МК с АЦП посредством SPI....

RS-232. Передача и прием данных
Подскажите пожалуйста. не опытному программисту в чем может быть проблема с этим кодом: вставляю в...

Одновременная передача и прием данных
Здравствуйте! При попытки передать и получить данные одновременно, возникает проблема, т.е. при...

COM-USB приём, передача данных
Добрый день! Такая проблема: данные с микроконтроллера ATMEGA 128 идут по RS232C после чего...

Stm32 передача данных по UART
Здравствуйте, начинаю разбираться с библиотекой HAL. МК Stm32f407ig, IDE SW4STM32 Создала в кубе...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.