Skip to content

Commit 136f7e9

Browse files
committed
apps: Add Simple SPI Nanopb example
Application based on example from Nanopb repository. Communicates over SPI and shows the basic Nanopb API usage.
1 parent 7561c81 commit 136f7e9

File tree

6 files changed

+460
-0
lines changed

6 files changed

+460
-0
lines changed

apps/nanopb_simple_spi/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
### Nanopb SPI Simple Example
2+
3+
##### Overview
4+
********
5+
6+
This application is based on Nanopb example called Simple.
7+
It contains source and header file generated with Nanopb.
8+
The header file defines one structure (message) with one int field
9+
called lucky_number. The application shows how to use basic Nanopb API and
10+
configures the SPI to send the message and receive it on the other device.
11+
Two devices are required for this to work:
12+
1. MASTER - encodes and sends one message per second over the SPI.
13+
After sending one message the lucky_number is incremented, encoded
14+
and sent again. Toggles the LED after each sent message.
15+
2. SLAVE - after receiving the message it decodes it and prints
16+
the lucky_number value. Toggles the LED after each received
17+
message.

apps/nanopb_simple_spi/pkg.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
20+
pkg.name: apps/nanopb_simple_spi
21+
pkg.type: app
22+
pkg.description: Nanopb SPI example
23+
pkg.author: "Apache Mynewt <[email protected]>"
24+
pkg.homepage: "http://mynewt.apache.org/"
25+
pkg.keywords:
26+
27+
pkg.deps:
28+
- "@apache-mynewt-core/sys/console"
29+
- "@apache-mynewt-core/kernel/os"
30+
- "@apache-mynewt-core/sys/config"
31+
- "@apache-mynewt-core/sys/log"
32+
- "@apache-mynewt-core/sys/stats"
33+
- "@apache-mynewt-core/encoding/nanopb"

apps/nanopb_simple_spi/src/main.c

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include <console/console.h>
21+
#include <assert.h>
22+
#include <pb_decode.h>
23+
#include <pb_encode.h>
24+
#include "simple.pb.h"
25+
#include "os/mynewt.h"
26+
#include "bsp/bsp.h"
27+
#include "hal/hal_gpio.h"
28+
#include "hal/hal_spi.h"
29+
#include "stats/stats.h"
30+
#include "config/config.h"
31+
#ifdef ARCH_sim
32+
#include <mcu/mcu_sim.h>
33+
#endif
34+
35+
/* Task 1 */
36+
#define TASK1_PRIO (1)
37+
#define TASK1_STACK_SIZE OS_STACK_ALIGN(1024)
38+
struct os_task task1;
39+
40+
/* For LED toggling */
41+
int g_led_pin;
42+
43+
#define SPI_BAUDRATE 500
44+
#define MESSAGE_BUFF_SIZE 5
45+
46+
#if MYNEWT_VAL(SPI_0_MASTER) || MYNEWT_VAL(SPI_1_MASTER) || MYNEWT_VAL(SPI_2_MASTER)
47+
#define SPI_MASTER 1
48+
#define SPI_SS_PIN (MYNEWT_VAL(PB_SPI_SS_PIN))
49+
#if SPI_SS_PIN < 0
50+
#error "PB_SPI_SS_PIN must be set in the target config."
51+
#endif
52+
#define SPI_M_NUM (MYNEWT_VAL(PB_SPI_M_NUM))
53+
#endif
54+
55+
#if MYNEWT_VAL(SPI_0_SLAVE) || MYNEWT_VAL(SPI_1_SLAVE) || MYNEWT_VAL(SPI_2_SLAVE)
56+
#define SPI_SLAVE 1
57+
#define SPI_S_NUM (MYNEWT_VAL(PB_SPI_S_NUM))
58+
#endif
59+
60+
#if defined(SPI_MASTER) && defined(SPI_SLAVE)
61+
#if SPI_M_NUM == SPI_S_NUM
62+
#error "SPI_M_NUM and SPI_S_NUM cannot be the same."
63+
#endif
64+
#endif
65+
66+
#ifdef SPI_MASTER
67+
void
68+
spi_irqm_handler(void *arg, int len)
69+
{
70+
hal_gpio_write(SPI_SS_PIN, 1);
71+
}
72+
73+
void
74+
spim_cfg(int spi_num)
75+
{
76+
struct hal_spi_settings my_spi;
77+
78+
my_spi.data_order = HAL_SPI_MSB_FIRST;
79+
my_spi.data_mode = HAL_SPI_MODE0;
80+
my_spi.baudrate = SPI_BAUDRATE;
81+
my_spi.word_size = HAL_SPI_WORD_SIZE_8BIT;
82+
assert(hal_spi_config(spi_num, &my_spi) == 0);
83+
}
84+
#endif
85+
86+
#ifdef SPI_SLAVE
87+
struct os_sem g_spi_sem;
88+
int32_t g_lucky_number;
89+
uint8_t g_spi_rx_buf[MESSAGE_BUFF_SIZE];
90+
91+
void
92+
spi_irqs_handler(void *arg, int len)
93+
{
94+
/* Allocate space for the decoded message. */
95+
SimpleMessage message = SimpleMessage_init_zero;
96+
pb_istream_t stream;
97+
bool status;
98+
99+
/* Create a stream that reads from the buffer. */
100+
stream = pb_istream_from_buffer(g_spi_rx_buf, (size_t)len);
101+
/* Now we are ready to decode the message. */
102+
status = pb_decode(&stream, SimpleMessage_fields, &message);
103+
/* Check for errors... */
104+
assert(status);
105+
106+
/* Save the data contained in the message. */
107+
g_lucky_number = message.lucky_number;
108+
109+
os_sem_release(&g_spi_sem);
110+
}
111+
112+
void
113+
spis_cfg(int spi_num)
114+
{
115+
struct hal_spi_settings my_spi;
116+
117+
my_spi.data_order = HAL_SPI_MSB_FIRST;
118+
my_spi.data_mode = HAL_SPI_MODE0;
119+
my_spi.baudrate = SPI_BAUDRATE;
120+
my_spi.word_size = HAL_SPI_WORD_SIZE_8BIT;
121+
assert(hal_spi_config(spi_num, &my_spi) == 0);
122+
123+
hal_spi_set_txrx_cb(spi_num, spi_irqs_handler, NULL);
124+
}
125+
#endif
126+
127+
#ifdef SPI_MASTER
128+
void
129+
spim_task_handler(void *arg)
130+
{
131+
/* Allocate space on the stack to store the message data.
132+
*
133+
* Nanopb generates simple struct definitions for all the messages.
134+
* - check out the contents of simple.pb.h!
135+
* It is a good idea to always initialize your structures
136+
* so that you do not have garbage data from RAM in there.
137+
*/
138+
SimpleMessage message = SimpleMessage_init_zero;
139+
/* This is the buffer where we will store our message. */
140+
uint8_t buffer[MESSAGE_BUFF_SIZE];
141+
pb_ostream_t stream;
142+
bool status;
143+
int rc;
144+
145+
/* Initialize the lucky number */
146+
message.lucky_number = 0;
147+
148+
/* Set the led pin */
149+
g_led_pin = LED_BLINK_PIN;
150+
hal_gpio_init_out(g_led_pin, 1);
151+
152+
/* Configure SS pin */
153+
hal_gpio_init_out(SPI_SS_PIN, 1);
154+
spim_cfg(SPI_M_NUM);
155+
156+
/* Set up the callback to use when non-blocking API used */
157+
hal_spi_set_txrx_cb(SPI_M_NUM, spi_irqm_handler, NULL);
158+
hal_spi_enable(SPI_M_NUM);
159+
160+
while (1) {
161+
/* Send non-blocking */
162+
hal_gpio_write(SPI_SS_PIN, 0);
163+
/* Create a stream that will write to our buffer. */
164+
stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
165+
/* Increment the lucky number */
166+
message.lucky_number++;
167+
/* Now we are ready to encode the message! */
168+
status = pb_encode(&stream, SimpleMessage_fields, &message);
169+
/* Then just check for any errors... */
170+
assert(status);
171+
172+
rc = hal_spi_txrx_noblock(SPI_M_NUM, buffer, NULL, (int)stream.bytes_written);
173+
assert(!rc);
174+
175+
/* Wait one second */
176+
os_time_delay(OS_TICKS_PER_SEC);
177+
178+
/* Toggle the LED */
179+
hal_gpio_toggle(g_led_pin);
180+
}
181+
}
182+
#endif
183+
184+
#ifdef SPI_SLAVE
185+
186+
void
187+
spis_task_handler(void *arg)
188+
{
189+
/* This is the buffer where we will store our message. */
190+
int rc;
191+
192+
g_led_pin = LED_BLINK_PIN;
193+
hal_gpio_init_out(g_led_pin, 1);
194+
195+
spis_cfg(SPI_S_NUM);
196+
hal_spi_enable(SPI_S_NUM);
197+
198+
/* Make the default character 0x77 */
199+
hal_spi_slave_set_def_tx_val(SPI_S_NUM, 0x77);
200+
201+
while (1) {
202+
rc = hal_spi_txrx_noblock(SPI_S_NUM, NULL, g_spi_rx_buf, MESSAGE_BUFF_SIZE);
203+
assert(rc == 0);
204+
205+
os_sem_pend(&g_spi_sem, OS_TIMEOUT_NEVER);
206+
207+
console_printf("Lucky number: %ld\n", g_lucky_number);
208+
209+
/* Toggle the LED */
210+
hal_gpio_toggle(g_led_pin);
211+
}
212+
}
213+
#endif
214+
215+
/**
216+
* init_tasks
217+
*
218+
* Called by main.c after sysinit(). This function performs initializations
219+
* that are required before tasks are running.
220+
*
221+
* @return int 0 success; error otherwise.
222+
*/
223+
static void
224+
init_tasks(void)
225+
{
226+
os_stack_t *pstack;
227+
228+
#if defined(SPI_MASTER)
229+
pstack = malloc(sizeof(os_stack_t) * TASK1_STACK_SIZE);
230+
assert(pstack);
231+
232+
os_task_init(&task1, "spim", spim_task_handler, NULL, TASK1_PRIO,
233+
OS_WAIT_FOREVER, pstack, TASK1_STACK_SIZE);
234+
#endif
235+
236+
#if defined(SPI_SLAVE)
237+
/* Initialize semaphore */
238+
os_sem_init(&g_spi_sem, 0);
239+
240+
pstack = malloc(sizeof(os_stack_t) * TASK1_STACK_SIZE);
241+
assert(pstack);
242+
243+
os_task_init(&task1, "spis", spis_task_handler, NULL, TASK1_PRIO,
244+
OS_WAIT_FOREVER, pstack, TASK1_STACK_SIZE);
245+
#endif
246+
}
247+
248+
/**
249+
* main
250+
*
251+
* The main task for the project. This function initializes the packages, calls
252+
* init_tasks to initialize additional tasks (and possibly other objects),
253+
* then starts serving events from default event queue.
254+
*
255+
* @return int NOTE: this function should never return!
256+
*/
257+
int
258+
mynewt_main(int argc, char **argv)
259+
{
260+
int rc;
261+
262+
sysinit();
263+
init_tasks();
264+
265+
while (1) {
266+
os_eventq_run(os_eventq_dflt_get());
267+
}
268+
/* Never returns */
269+
assert(0);
270+
271+
return rc;
272+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/* Automatically generated nanopb constant definitions */
21+
/* Generated by nanopb-1.0.0-dev */
22+
23+
#include "simple.pb.h"
24+
#if PB_PROTO_HEADER_VERSION != 40
25+
#error Regenerate this file with the current version of nanopb generator.
26+
#endif
27+
28+
PB_BIND(SimpleMessage, SimpleMessage, AUTO)
29+
30+
31+

0 commit comments

Comments
 (0)