Skip to content

Commit 5a9272f

Browse files
committed
Frist commit
Signed-off-by: Imre Deak <[email protected]>
0 parents  commit 5a9272f

8 files changed

+284
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build
2+
.*.swp

CMakeLists.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.13.1)
4+
5+
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
6+
project(stm32-spi)
7+
8+
target_sources(app PRIVATE src/main.c)

README.rst

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
.. _stm32-spi:
2+
3+
stm32-spi
4+
#########
5+
6+
Overview
7+
********
8+
A simple example of using an *STM32 Nucleo-F411RE* board to transfer data over
9+
the SPI bus.
10+
11+
Building and Running
12+
********************
13+
14+
First set up *Zephyr* according to its `Getting Started Guide <https://docs.zephyrproject.org/latest/getting_started/index.html#getting-started>`_ using its *West* tool.
15+
16+
For this project I haven't used the `Zephyr SDK <https://docs.zephyrproject.org/latest/getting_started/installation_linux.html#install-the-zephyr-software-development-kit-sdk>`_, rather (on Ubuntu/cosmic) just followed the `Building on Linux without the Zephyr SDK <https://docs.zephyrproject.org/latest/getting_started/installation_linux.html#building-on-linux-without-the-zephyr-sdk>`_ by installing *gcc-arm-none-eabi* and setting *CROSS_COMPILE* and *ZEPHYR_TOOLCHAIN_VARIANT*
17+
accordingly (done by `configure.sh <https://github.com/ideak/zephyr-stm32-spi/blob/master/configure.sh>`_ below, for details see the *Zephyr* documentation).
18+
19+
Based on the above after installing *Zephyr* and *gcc-arm-none-eabi*, you can just run inside the checked out dir of this repo:
20+
21+
.. code:: bash
22+
23+
$ configure.sh
24+
25+
to create the *build* dir and the build scripts within. Then - either initially or whenever you change the source:
26+
27+
.. code:: bash
28+
29+
$ cd build
30+
$ ninja
31+
$ ninja flash
32+
33+
to build and flash the image to your board.
34+
35+
Going further you may also want to customize the *Zephyr* core configuration - and then rebuild the image as you did above - with:
36+
37+
.. code:: bash
38+
39+
$ ninja menuconfig
40+
41+
for instance to enable debugging, choose another SPI module instead of SPI1 the app uses by default, or just to get furhter ideas of all the cool stuff you can do with *Zephyr*. Or just to have a Déjà vu experience ;)
42+
43+
See the comment in `src/main.c <https://github.com/ideak/zephyr-stm32-spi/blob/master/src/main.c>`_ for details about the board specific SPI pin config and MCU specific low-level bus programming (both taken care for us by the *Zephyr* core).
44+
45+
You may also find it useful to read about the *Nucleo-F411RE* board's `pinout layout <https://os.mbed.com/platforms/ST-Nucleo-F411RE>`_ and the *STM32-F411RE* MCU's `datasheet <https://www.st.com/resource/en/datasheet/stm32f411ce.pdf>`_ and `reference manual <https://www.st.com/resource/en/reference_manual/dm00119316.pdf>`_.
46+
47+
Sample Output
48+
=============
49+
.. code:: bash
50+
51+
$ cu -l /dev/ttyACM0
52+
Connected.
53+
***** Booting Zephyr OS zephyr-v1.14.0-719-gbba534299244 *****
54+
Starting stm32-spi on nucleo_f411re
55+
56+
.. image:: scope.png

configure.sh

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
stm32_spi_check_env()
2+
{
3+
if [ -z "${ZEPHYR_BASE+x}" ]; then
4+
echo -e \
5+
"ZEPHYR_BASE is not set.\n"\
6+
"Please source zephyr-env.sh from your <Zephyr project dir>/zephyr directory"
7+
8+
return 1
9+
fi
10+
11+
if [ ! -d src ]; then
12+
echo -e \
13+
"Please source this file from your Zephyr app base dir"
14+
15+
return 1
16+
fi
17+
18+
if [ -d build ]; then
19+
echo -e \
20+
"The build directory already exist, remove it first if you want reconfigure it"
21+
22+
return 1
23+
fi
24+
25+
if [ -e build ]; then
26+
echo -e \
27+
"You use 'build' as something else than your build dir"
28+
29+
return 1
30+
fi
31+
32+
return 0
33+
}
34+
35+
stm32_spi_do_setup()
36+
{
37+
local err
38+
39+
export CROSS_COMPILE=/usr/bin/arm-none-eabi-
40+
export ZEPHYR_TOOLCHAIN_VARIANT=cross-compile
41+
42+
mkdir build
43+
cd build
44+
45+
cmake -GNinja -DBOARD=nucleo_f411re ..
46+
err=$?
47+
48+
cd ..
49+
50+
if [ $err -ne 0 ]; then
51+
echo Removing build
52+
rm -r build
53+
fi
54+
55+
return $err
56+
}
57+
58+
if stm32_spi_check_env && stm32_spi_do_setup; then
59+
echo -e \
60+
"Setup complete, you can now do:\n"\
61+
"\tcd build\n"\
62+
"\tninja\n"\
63+
"\tninja flash"
64+
fi

prj.conf

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CONFIG_SPI=y

sample.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
sample:
2+
description: stm32-spi, SPI example on STM32F411RE
3+
application
4+
name: stm32-spi
5+
common:
6+
tags: introduction
7+
harness: console
8+
harness_config:
9+
type: one_line
10+
regex:
11+
- "stmp32-spi (.*)"
12+
tests:
13+
sample.stm32-spi:
14+
tags: introduction

scope.png

8.84 KB
Loading

src/main.c

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* SPDX-License-Identifier: SPDX-License-Identifier: Apache-2.0
3+
* Author: Imre Deak <[email protected]>
4+
*
5+
* This simple app demonstrates how to use Zephyr for SPI transfers.
6+
*
7+
* It uses the SPI1 bus which on the STM32F411RE has the following pinout
8+
* configuration (by default configured that way by the Zephyr core):
9+
*
10+
* SPI1_SCK: PA5 (alternative pin: PB3)
11+
* SPI1_MISO: PA6 (alternative pin: PB4)
12+
* SPI1_MOSI: PA7 (alternative pin: PB5)
13+
* SPI1_NSS: PA4 (alternative pin: PA15)
14+
*
15+
* See
16+
*
17+
* https://www.st.com/resource/en/datasheet/stm32f411ce.pdf
18+
*
19+
* Chapter 4 "Pinouts and pin description" for more details on configuring the
20+
* pins for alternate functions and
21+
*
22+
* https://os.mbed.com/platforms/ST-Nucleo-F411RE
23+
*
24+
* "Morpho headers" for locating the pins on the board.
25+
*
26+
* The SPI bus will be used in master (non-TI aka Motorola) mode, see the
27+
* STM32F411xC/E reference manual (RM0383) at
28+
*
29+
* https://www.st.com/resource/en/reference_manual/dm00119316.pdf
30+
*
31+
* Chapter 20.3.3 "Configuring the SPI in master mode" and
32+
* 20.3.5 "Data transmission and reception procedures"/
33+
* "Start sequence in master mode"
34+
* for the corresponding low-level programming (done by Zephyr internally).
35+
*
36+
* For simplicity the NSS line (chip select) will be operated in
37+
* "hardware mode" see the reference manual Chapter 20.3.1 in general and
38+
* within that specifically the "Slave select (NSS) pin management" part. In
39+
* practice this means that the HW itself will assert the NSS line whenever it
40+
* transmits data and de-asserts it at the end of the transfer.
41+
*
42+
* For the register flags related to the above master mode and NSS setup see
43+
* the reference manual
44+
* Chapter 20.5.1 "SPI control register 1 (SPI_CR1)" SSM/SSI/MSTR and
45+
* Chapter 20.5.2 "SPI control register 2 (SPI_CR2)" SSOE flags.
46+
*
47+
* The NSS line needs to be pulled up but Zephyr doesn't configure an internal
48+
* pull-up for the corresponding PA4 pin by default. Since this app is geared
49+
* for an easy setup-and-measure with a scope scenario it will configure an
50+
* internal pull-up on the pin during init in stm32_spi_setup_nss_pin().
51+
*
52+
* If your circuit has an external pull-up resistor then you don't need (or
53+
* even should not) configure the internal one (achieved by not calling
54+
* stm32_spi_setup_nss_pin()).
55+
*
56+
* As an alternative to the above NSS "hardware mode" it's also possible to
57+
* use any available pin in GPIO mode to provide for the SPI chip select
58+
* functionality. In this case struct spi_config::cs needs to be initialized
59+
* appropriately in main(), which will make Zephyr configure the SPI module in
60+
* the NSS "software mode". See the reference manual for details for the
61+
* corresponding low-level programming. This app itself would then need to
62+
* assert/de-assert the given GPIO around each SPI transfer.
63+
*
64+
* Probably for a real use case you want to use the NSS "software mode"
65+
* because that's the only way you can:
66+
* - control the timing of the chip select signal
67+
* - configure the CS signal as positive-asserted (rare case)
68+
* - use more than one CS signal to control multiple slaves
69+
* The "hardware mode" uses some kind of a fixed timing, supports only the
70+
* standard negative-asserted CS logic and a single CS signal.
71+
*/
72+
#include <string.h>
73+
#include <spi.h>
74+
75+
#include <pinmux/stm32/pinmux_stm32.h>
76+
77+
static int stm32_spi_send(struct device *spi,
78+
const struct spi_config *spi_cfg,
79+
const uint8_t *data, size_t len)
80+
{
81+
const struct spi_buf_set tx = {
82+
.buffers = &(const struct spi_buf){
83+
.buf = (uint8_t *)data,
84+
.len = len,
85+
},
86+
.count = 1,
87+
};
88+
89+
return spi_write(spi, spi_cfg, &tx);
90+
}
91+
92+
static int stm32_spi_send_str(struct device *spi,
93+
const struct spi_config *spi_cfg,
94+
const unsigned char *str)
95+
{
96+
return stm32_spi_send(spi, spi_cfg, str, strlen(str));
97+
}
98+
99+
static void stm32_spi_setup_nss_pin(void)
100+
{
101+
static const struct pin_config pin_config = {
102+
.pin_num = STM32_PIN_PA4,
103+
.mode = STM32_PINMUX_ALT_FUNC_5 | STM32_PUSHPULL_PULLUP,
104+
};
105+
106+
stm32_setup_pins(&pin_config, 1);
107+
}
108+
109+
void main(void)
110+
{
111+
struct spi_config spi_cfg = {};
112+
struct device *spi;
113+
int err;
114+
115+
printk("Starting stm32-spi on %s\n", CONFIG_BOARD);
116+
117+
stm32_spi_setup_nss_pin();
118+
119+
spi = device_get_binding("SPI_1");
120+
if (!spi) {
121+
printk("Could not find SPI driver\n");
122+
return;
123+
}
124+
125+
spi_cfg.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
126+
SPI_OP_MODE_MASTER;
127+
128+
spi_cfg.frequency = 1000000U;
129+
130+
for (;;) {
131+
err = stm32_spi_send_str(spi, &spi_cfg, "HELLO!");
132+
if (err)
133+
break;
134+
k_sleep(1);
135+
}
136+
137+
if (err)
138+
printk("SPI send error %d\n", err);
139+
}

0 commit comments

Comments
 (0)