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.

[ARM] NRF24L01+ and STM32F0 - using SPI, HAL and CubeMX

Status
Not open for further replies.

matti0010

Newbie level 5
Joined
Feb 5, 2017
Messages
9
Helped
4
Reputation
8
Reaction score
4
Trophy points
3
Activity points
164
Hello,

I sit and looking mistake for 5 days... I trying using NRF24L01+ and STM32F0DISCOVERY. My library working on ATmega8, but when i trying using this function in STM32 NRF no working... I replace methods communication (other in AVR, other in STM). OK, first code:

main.c

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
int main(void)
{
 
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration----------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
 
  /* USER CODE BEGIN 2 */
    HAL_SPI_Init(&hspi1);
    HAL_UART_Init(&huart1);
    uint8_t RX0_adres[5] = { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7 };
    uint8_t RX1_adres[5] = { 0xc2, 0xc2, 0xc2, 0xc2, 0xc2 };
    uint8_t data[] = { 0x01, 0, 0, 0, 0 }; //dane do wyslania
    uint8_t flaga = 0;
    uint8_t koniec_linii[2] = { 13, 10 }; //pomocnicze
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    NRF24_init();
    Set_Tx_Adr(RX0_adres);
    Set_Rx_Adr(RX_ADDR_P1, RX1_adres);
    Set_Px_Adr(RX_ADDR_P2, 0x32);
    Set_Px_Adr(RX_ADDR_P3, 0x33);
    Set_Px_Adr(RX_ADDR_P4, 0x34);
    Set_Px_Adr(RX_ADDR_P5, 0x35);
    tryb_RX();
    while (1) {
        /*if(flaga==0)
         {
         wyslij_dane(data, ((sizeof data)/(sizeof *data)), ACK);
         while(jest_wysylane());
         tryb_RX();
         flaga=1;
         }*/
        //if (dane_gotowe()) //czy jest cos do odebrania
        //{
        //  odbierz_dane(data); //pobierz dane z FIFO
 
            HAL_UART_Transmit(&huart1, data, 5, 100);
            HAL_Delay(1000);
        //  tryb_RX();
            // flaga=0;
        //}
  /* USER CODE END WHILE */
 
  /* USER CODE BEGIN 3 */
 
    }
  /* USER CODE END 3 */
 
}



NRF23L01.h


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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 * NRF24L01.h
 *
 *  Created on: 30 sty 2017
 *      Author: Mateusz
 */
 
#ifndef NRF24L01_H_
#define NRF24L01_H_
 
//mnemoniki instrukcji
#define READ_REG                0x00//odczyt komend w rejestrze
#define WRITE_REG               0x20//zapis komend do rejestru
#define RD_RX_PAYLOAD           0x61//dlugosc rejestru danych w RX
#define WR_TX_PAYLOAD           0xA0//dlugosc rejestru danych w TX
#define FLUSH_TX                0xE1
#define FLUSH_RX                0xE2
#define REUSE_TX_PL             0xE3//powtorzenie ostatniego pakietu
#define R_RX_PL_WID             0x60//odczyt dlugosci danych
#define W_ACK_PAYLOAD           0xA8//specyfikacja rur (pipe)
#define W_TX_PAYLOAD_NOACK      0xB0//wyslanie dlugosci danych z statusem braku potwierdzenia odbioru
#define NOP                     0xFF
 
//rejestr STATUSu
#define STATUS_RBANK    0x80
#define STATUS_RX_DR    0x40
#define STATUS_TX_DS    0x20
#define STATUS_MAX_RT   0x10
#define STATUS_TX_FULL  0x01
 
//mapa pamieci i mnemoniki
#define CONFIG      0x00
#define EN_AA       0x01
#define EN_RX_ADDR  0x02
#define SETUP_AW    0x03
#define SETUP_RETR  0x04
#define RF_CH       0x05
#define RF_SETUP    0x06
#define STATUS      0x07
#define OBSERVE_TX  0x08
#define CD          0x09
#define RX_ADDR_P0  0x0A
#define RX_ADDR_P1  0x0B
#define RX_ADDR_P2  0x0C
#define RX_ADDR_P3  0x0D
#define RX_ADDR_P4  0x0E
#define RX_ADDR_P5  0x0F
#define TX_ADDR     0x10
#define RX_PW_P0    0x11
#define RX_PW_P1    0x12
#define RX_PW_P2    0x13
#define RX_PW_P3    0x14
#define RX_PW_P4    0x15
#define RX_PW_P5    0x16
#define FIFO_STATUS 0x17
#define DYNPD       0x1C
#define FEATURE     0x1D
 
//status dla FIFO
#define FIFO_STATUS_TX_REUSE    0x40
#define FIFO_STATUS_TX_FULL     0x20
#define FIFO_STATUS_TX_EMPTY    0x10
#define FIFO_STATUS_RX_FULL     0x02
#define FIFO_STATUS_RX_EMPTY    0x01
 
//odblokowanie auto-potwierdzenia odbioru
#define ENAA_P5     5
#define ENAA_P4     4
#define ENAA_P3     3
#define ENAA_P2     2
#define ENAA_P1     1
#define ENAA_P0     0
 
//rejestr konfiguracyjny
#define MASK_RX_DR  6
#define MASK_TX_DS  5
#define MASK_MAX_RT 4
#define EN_CRC      3
#define CRC0        2
#define PWR_UP      1
#define PRIM_RX     0
 
//odblokowanie adresowania RX
#define ERX_P5      5
#define ERX_P4      4
#define ERX_P3      3
#define ERX_P2      2
#define ERX_P1      1
#define ERX_P0      0
 
//odblokowanie dlugosci adresowania
#define AW          0
 
//ustawienie automatycznej retransmisji
#define ARD         4
#define ARC         0
 
//stan FIFO
#define TX_REUSE    6
#define FIFO_FULL   5
#define TX_EMPTY    4
#define RX_FULL     1
#define RX_EMPTY    0
 
//dynamiczna dlugosc
#define DPL_P0      0
#define DPL_P1      1
#define DPL_P2      2
#define DPL_P3      3
#define DPL_P4      4
#define DPL_P5      5
 
//rejestr wlasciwosci
#define EN_DPL      2
#define EN_ACK_PAY  1
#define EN_DYN_ACK  0
 
//ustawienie rejestru RF
#define RF_DR_LOW   5
#define PLL_LOCK    4
#define RF_DR       3
#define RF_PWR      1
 
//rejestr do obserwacji transmitowania
#define PLOS_CNT    4
#define ARC_CNT     0
 
 
 
//glowny rejestr statusu
#define RX_DR       6
#define TX_DS       5
#define MAX_RT      4
#define RX_P_NO     1
#define TX_FULL     0
 
//definicje (nie)potwierdzenia odbioru
#define NOACK                   0x00
#define ACK                     0x01
 
//ustawienie CE i CS na 0 lub 1
#define CE_l    HAL_GPIO_WritePin(SPI1_CE_GPIO_Port, SPI1_CE_Pin, RESET)
#define CS_l    HAL_GPIO_WritePin(SPI1_CSN_GPIO_Port, SPI1_CSN_Pin, RESET)
#define CE_h    HAL_GPIO_WritePin(SPI1_CE_GPIO_Port, SPI1_CE_Pin, SET)
#define CS_h    HAL_GPIO_WritePin(SPI1_CSN_GPIO_Port, SPI1_CSN_Pin, SET)
 
void NRF24_init(void);
uint8_t SPI_reg(uint8_t reg, uint8_t val);
uint8_t SPI_r_w(uint8_t x);
void Set_Tx_Adr(uint8_t* adr);
void SPI_zapis_buf(uint8_t reg, uint8_t *buf, uint8_t dlugosc);
void Set_Rx_Adr(uint8_t rura, uint8_t * adr);
void Set_Px_Adr(uint8_t rura, uint8_t adr);
void wyslij_dane(uint8_t* dane, uint8_t ilosc, uint8_t ack);
void tryb_TX(void);
uint8_t daj_status(void);
uint8_t jest_wysylane(void);
void tryb_RX(void);
uint8_t dane_gotowe(void);
uint8_t RX_FIFO_pusty(void);
void odbierz_dane(uint8_t* data);
void SPI_odczyt_buf(uint8_t reg, uint8_t *buf, uint8_t dlugosc);
void Flush_RX(void);
 
#endif /* NRF24L01_H_ */



NRF24L01.c


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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*
 * NRF24L01.c
 *
 *  Created on: 30 sty 2017
 *      Author: Mateusz
 */
 
 
#include "stm32f0xx_hal.h"
#include "spi.h"
#include "gpio.h"
#include "NRF24L01.h"
 
const uint16_t NRF24_reg[] =//ustawianie rejestrow
{
    //rejestr CONFG: bez przerwan od RX, TX, MAX_RT, wlaczone CRC, 2bitowe kodowanie CRC, POWER DOWN, RX/TX kontrolowane PTX
    (CONFIG<<8)         |   (1<<MASK_RX_DR) | (1<<MASK_TX_DS) | (1<MASK_MAX_RT) | (1<<EN_CRC) | (1<<CRC0) | (0<<PWR_UP) | (0<<PRIM_RX),
    //rejestr EN_AA: odblokowanie potwierdzenia danych dla każdego z 5 rur transmisyjnych
    (EN_AA<<8)          |   0x3F,
    //rejestr EN_RX_ADDR: odblokowanie włączenia adresowania RX dla wszystkich 5 rur (pipes)
    (EN_RX_ADDR<<8)     |   0x3F,
    //rejestr SETUP_AW: 5-bitowe adresowanie, wspolne dla wszystkich rur
    (SETUP_AW<<8)       |   0x03,
    //rejestr SETUP_RETR: odpowiada za automatyczna retransmisje;
    //ARC=0x0F - 15razy bedzie powtarzania retransmisja; ARD=0x03 - czekam 1ms miedzy kolejnymi retransmisjami
    (SETUP_RETR<<8)     |   (0x03<<ARD)|(0x0F<<ARC),
    //rejestr RF_CH: ustaw czestotliwosc dla kanalu RF
    //(RF_CH<<8)            |   2,
    (RF_CH<<8)          |   0x60,
    //rejestr RF_SETU: PLL wylaczone(RF_DR_LOW);
    //predkosc przesylu w powietrzu 250kbps(RF_DR na 0 lecz RF_DR_LOW na 1 co daje 250kbps);
    //moc wyjsciowa 0dBm (RF_PWR)
    (RF_SETUP<<8)       |   (1<<RF_DR_LOW)|(0<<RF_DR)|(0x03<<RF_PWR),
    //rejestr STATUS: czyszczenie rejestru
    (STATUS<<8)         |   0xFF,
    //rejestr OBSERVE_TX: tylko do odczytu, informuje o utraconych pakietach, licznik ilosci retransmisji
    (OBSERVE_TX<<8)     |   0x00,
    //rejestr CD: tylko do odczytu, detekcja nosnej sygnalu
    (CD<<8)             |   0x00,
    //dane adresowe dla rur (od 0 do 5) od RX; liczba bajtow musi byc wpisana tak jak jest ustawiona w SETUP_AW
    (RX_ADDR_P0<<8)     |   0xE7,
    (RX_ADDR_P1<<8)     |   0xC2,
    (RX_ADDR_P2<<8)     |   0xC3,
    (RX_ADDR_P3<<8)     |   0xC4,
    (RX_ADDR_P4<<8)     |   0xC5,
    (RX_ADDR_P5<<8)     |   0xC6,
    //rejestr TX_ADDR: adres transmisji, uzywane gdy korzysta sie z PTX
    (TX_ADDR<<8)        |   0xE7,
    //rejestr TX_PW_Px (x=0..5): liczba bajtów w rurze x dla  RX, jezeli 0 to rura nie uzywana
    (RX_PW_P0<<8)       |   0x20,
    (RX_PW_P1<<8)       |   0x20,
    (RX_PW_P2<<8)       |   0x20,
    (RX_PW_P3<<8)       |   0x20,
    (RX_PW_P4<<8)       |   0x20,
    (RX_PW_P5<<8)       |   0x20,
    //rejestr FIFO: rejestr statusu FIFO, tylko do odczytu
    (FIFO_STATUS<<8)    |   0x00,
    //ustawienie dynamicznej dlugosci bloku danych dla rur, wymaga odblokowania EN_AA dla kazdej rury i EN_DPL
    (DYNPD<<8)          |   0x3F,
    //rejestr FEATURE: rejestr funkcji; EN_DPL - odblokowanie dynamicznej dlugosci bloku danych;
    //EN_ACK_PAY - odblokowanie bloku danych z potwierdzeniem (ACK);
    //EN_DYN_ACK - odblokowuje komende W_TX_PAYLOAD_NOACK
    (FEATURE<<8)        |   (1<<EN_DPL) | (1<<EN_ACK_PAY) | (1<<EN_DYN_ACK) //
};
 
void NRF24_init(void)
{
    uint8_t i, a;
    uint16_t temp;
 
    //ile rejestrow ma ustawic
    a=(sizeof(NRF24_reg)/2);
    //inicjalizacja rejestrow NRF
    for(i=0;i<a;i++)
    {
        //odczyt zawartości z flash
        temp = NRF24_reg[i];
        SPI_reg((WRITE_REG|(temp>>8)), (temp&0xFF));
    }
}
 
uint8_t SPI_reg(uint8_t reg, uint8_t val)
{
    CS_l;                   // CSN na poziom niski, inicjalizacja komunikacji po SPI z NRF
    SPI_r_w(reg);            // Select register to read from..
    val = SPI_r_w(val);     // ..then read register value
    CS_h;                   // CSN high, terminate SPI communication
    return(val);            // return register value
}
 
uint8_t SPI_r_w(uint8_t x)
{
    HAL_SPI_TransmitReceive(&hspi1, &x, &x, 1, 10);
    return x;
}
 
void Set_Tx_Adr(uint8_t* adr)
{
    //RX_ADDR_P0 musi byc ustawiony wysylajac addr w trybie automatycznego potwierdzenia dzialania
    SPI_zapis_buf(WRITE_REG|RX_ADDR_P0, adr, 5);
    SPI_zapis_buf(WRITE_REG|TX_ADDR, adr, 5);
}
 
void SPI_zapis_buf(uint8_t reg, uint8_t *buf, uint8_t dlugosc)
{
    uint8_t bajt;
    CS_l;//ustawia Cs na stan niski i inicjalizuje komunikacje po SPI
    SPI_r_w(reg);//wybiera odpowiedni rejestr i do niego zapisuje/odczytuje
    for(bajt=0; bajt < dlugosc; bajt++)//zapisuje do buforu
        SPI_r_w(buf[bajt]);
    CS_h;//ustawia CS w stan wysoki
}
 
void Set_Rx_Adr(uint8_t rura, uint8_t * adr)
{
    SPI_zapis_buf(WRITE_REG|rura, adr, 5);//5 - dlugosc adresu dla NRF24
}
 
void Set_Px_Adr(uint8_t rura, uint8_t adr)
{
    SPI_reg(WRITE_REG|rura, adr);
}
 
void wyslij_dane(uint8_t* dane, uint8_t ilosc, uint8_t ack)
{
    CE_l;//ustawia na Ce stan niski, wysylanie danych po SPI
    //ustaw NRF w tryb nadajnika i zalacz zasilanie w razie potrzeby
    if(ack) ack = WR_TX_PAYLOAD;//jezeli mamy ACK (makro) to z potwierdzeniem odbioru
    else ack = W_TX_PAYLOAD_NOACK;//jezeli mamy NOACK lub inna wartosc niz 1 nie jest z potwierdzeniem odbioru
    tryb_TX();//ustawienie TX
    SPI_zapis_buf(ack, dane, ilosc);//zapis dajnych do bufora SPI
    CE_h;//ustawian CE w stan wysoki i rozpoczynam transmisje
}
 
void tryb_TX(void)
{
    uint8_t val;
    SPI_reg(WRITE_REG|FLUSH_TX, 0);//zapis rejestrow NRF
    CE_l;//ustawiam CE w stan niski
    val = daj_status();//odczytuje wartosc rejestru statusu z NRF
    val = ((val|STATUS_TX_DS|STATUS_MAX_RT)&(~STATUS_RX_DR));
    SPI_reg(WRITE_REG|STATUS, val);//ustawiam rejestr statusu
    val = SPI_reg(CONFIG, 0);//odczytuje wartosc rejestru CONFIG
    //ustawienie bitu PWR_UP (zasilania), odblokowania CRC i RX_DR
    val = ((val&(~(1<<PRIM_RX)))|(1<<PWR_UP));
    SPI_reg(WRITE_REG|CONFIG, val);
    CE_h;//ustawiam CE w stan wysoki
}
 
uint8_t daj_status(void)
{
    uint8_t rv;
    CS_l;
    rv = SPI_r_w(NOP);
    CS_h;
    return rv;
}
 
uint8_t jest_wysylane()
{
    uint8_t status;
    status = daj_status();//odczytuje obecny status
    if(status&(STATUS_TX_DS|STATUS_MAX_RT))//jezeli zakonczono wysylanie badx po 15 probach nadal sie nie udalo
    {
        CE_l;//ustawiam CE w stan niski
        return 0;//jezeli skonczylo to zwraca 0
    }
    return 1;//jezeli nie skonczylo to zwraca 1
}
 
void tryb_RX(void)
{
    uint8_t val;
    SPI_reg(WRITE_REG|FLUSH_RX, 0);//zapis rejestrow NRF
    CE_l;//ustawiam CE w stan niski
    val = daj_status();//odczytuje wartosc rejestru statusu z NRF
    val = ((val|STATUS_RX_DR)&(~(STATUS_TX_DS | STATUS_MAX_RT)));
    SPI_reg(WRITE_REG|STATUS, val);//ustawiam rejestr statusu
    val = SPI_reg(CONFIG, 0);//odczytuje wartosc rejestru CONFIG
    //ustawiam PWR_UP (zasilanie), odblokowanie CRC i RX_DR
    val = val|(1<<PRIM_RX)|(1<<PWR_UP);
    SPI_reg(WRITE_REG | CONFIG, val);
    CE_h;//ustawiam CE w stan wysoki
}
 
uint8_t dane_gotowe(void)
{
    uint8_t status;
    status = daj_status();
    //sprawdzam RX_DR i FIFO, samo RX_DR nie wystarczy bo moga byc jeszcze jakies dane oczekujace
    if (status & STATUS_RX_DR)//jezeli cos jest to zwracam 1 i odczytuje
    {
        return 1;
    }
    status = !RX_FIFO_pusty();
    return status;
}
 
uint8_t RX_FIFO_pusty(void)
{
    uint8_t fifo;
    fifo = SPI_reg(FIFO_STATUS, 0);
    fifo = fifo & FIFO_STATUS_RX_EMPTY;
    return fifo;
}
 
void odbierz_dane(uint8_t* data)
{
    uint8_t dlugosc;
 
    dlugosc = SPI_reg(R_RX_PL_WID, 0);//odczytanie dlugosci liczby danych
    SPI_odczyt_buf(RD_RX_PAYLOAD, data, dlugosc);//odczyt danych
    SPI_reg(WRITE_REG|STATUS, STATUS_RX_DR);//zresetowanie rejestru statusu
    Flush_RX();
}
 
void SPI_odczyt_buf(uint8_t reg, uint8_t *buf, uint8_t dlugosc)
{
    uint8_t bajt;
    CS_l;//CS w stan niski
    SPI_r_w(reg);//wybor rejestru do zapisu
    for(bajt=0; bajt < dlugosc; bajt++)
        buf[bajt] = SPI_r_w(0);//odczyt po SPI
    CS_h;//CS w stan wysoki
}
 
void Flush_RX()
{
    SPI_reg(WRITE_REG | FLUSH_RX, 0);       //flush Rx
}



Comments is in polish language (or english).

Becouse I use CubeMX i take picture with settings:
1.png2.png3.png4.png

I read on other forum, that SPI in STM sometime no working. Mayby this is problem? I use this function to communication for SPI with NRF24L01+:


Code C - [expand]
1
2
3
4
5
uint8_t SPI_r_w(uint8_t x)
{
    HAL_SPI_TransmitReceive(&hspi1, &x, &x, 1, 10);
    return x;
}



I admit honestly, i don't understand total working NRF. I read many in this topis and i have chaos in my brain... If anyone can write to me have i must to send him (NRF) to obtain a particular effect i been verry grateful. I need help in organize knowledge NRF24L01+. Code on ATmega is working, so probably my problem is read/write with using SPI. In ATmega SI working with 1MHz osscillator and prescaler = 4 (so SPI have 250kHz).

Becouse I use CubeMX and System Workbench for STM32 i take all project.

Please help me with this problem :(
 

Attachments

  • SPI_NRF24L01_F0.rar
    4.6 MB · Views: 165

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top