Skip to content

Commit de3185c

Browse files
committed
CurieMailbox: refactor in preparation for Serial
The Serial class will soon be using the mailbox to transfer data between cores. This refactor prepares the library for that, by moving the HW access code into cores/arduino, and implementing per-channel callback functions
1 parent 50f30b3 commit de3185c

File tree

11 files changed

+613
-0
lines changed

11 files changed

+613
-0
lines changed

Diff for: cores/arduino/mailbox.cpp

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#include <string.h>
2+
#include "interrupt.h"
3+
#include "scss_registers.h"
4+
#include "mailbox.h"
5+
6+
#define CHANNEL_STS_MASK 0x1
7+
#define CHANNEL_INT_MASK 0x2
8+
#define CTRL_WORD_MASK 0x7FFFFFFF
9+
#define CHALL_STATUS_MASK 0xFFFF
10+
#define CHANNEL_STS_BITS (CHANNEL_STS_MASK | CHANNEL_INT_MASK)
11+
12+
/* Mailbox channel status register */
13+
#define IO_REG_MAILBOX_CHALL_STS (SCSS_REGISTER_BASE + 0xAC0)
14+
15+
typedef struct mbox_channel mbox_channel_t;
16+
typedef struct mbox_intmask mbox_intmask_t;
17+
18+
/* Represents the registers for a single mailbox channel */
19+
struct mbox_channel {
20+
uint32_t ctrl;
21+
uint32_t data[CHANNEL_DATA_WORDS];
22+
uint32_t sts;
23+
};
24+
25+
/* Mailbox interrupt mask; right now we only care about the
26+
* second byte, for SS mailbox interrupts (one bit per mailbox channel) */
27+
struct mbox_intmask {
28+
uint8_t lmt_intmask;
29+
uint8_t ss_intmask;
30+
uint8_t lmt_halt;
31+
uint8_t ss_halt;
32+
};
33+
34+
static volatile mbox_intmask_t *intmask;
35+
static volatile mbox_channel_t *mbox;
36+
static void (*callbacks[NUM_MAILBOX_CHANNELS])(CurieMailboxMsg);
37+
38+
void mailbox_register (int channel, void(*callback)(CurieMailboxMsg))
39+
{
40+
if (channel >= 0 && channel < NUM_MAILBOX_CHANNELS) {
41+
callbacks[channel] = callback;
42+
}
43+
}
44+
45+
void mailbox_unregister (int channel)
46+
{
47+
if (channel >= 0 && channel < NUM_MAILBOX_CHANNELS) {
48+
callbacks[channel] = 0;
49+
}
50+
}
51+
52+
void mailbox_disable_receive (int channel)
53+
{
54+
intmask->ss_intmask |= 1 << channel;
55+
}
56+
57+
void mailbox_enable_receive (int channel)
58+
{
59+
intmask->ss_intmask &= ~(1 << channel);
60+
}
61+
62+
static void do_callback (int channel, CurieMailboxMsg& msg)
63+
{
64+
void (*cb)(CurieMailboxMsg) = callbacks[channel];
65+
if (cb) {
66+
cb(msg);
67+
}
68+
}
69+
70+
static void mailbox_read (int channel, CurieMailboxMsg& msg)
71+
{
72+
unsigned int i;
73+
74+
/* Copy channel data into CurieMailboxMsg object */
75+
msg.id = mbox[channel].ctrl & CTRL_WORD_MASK;
76+
msg.channel = channel;
77+
78+
for (i = 0; i < CHANNEL_DATA_WORDS; ++i) {
79+
msg.data[i] = mbox[channel].data[i];
80+
}
81+
82+
/* Clear channel status & interrupt flags */
83+
mbox[channel].sts |= CHANNEL_STS_BITS;
84+
}
85+
86+
void mailbox_write (CurieMailboxMsg msg)
87+
{
88+
int i;
89+
uint32_t key;
90+
91+
/* Can't write if channel status flag is set */
92+
while ((mbox[msg.channel].sts & CHANNEL_STS_MASK));
93+
key = interrupt_lock();
94+
95+
/* Poplate channel payload */
96+
mbox[msg.channel].ctrl |= (msg.id & CTRL_WORD_MASK);
97+
for (i = 0; i < CHANNEL_DATA_WORDS; ++i) {
98+
mbox[msg.channel].data[i] = msg.data[i];
99+
}
100+
101+
/* Trigger interupt to host */
102+
mbox[msg.channel].ctrl |= ~(CTRL_WORD_MASK);
103+
104+
/* Wait for HW to set the channel status bit */
105+
while (!(mbox[msg.channel].sts & CHANNEL_STS_MASK));
106+
107+
/* Wait for destination processor to clear channel status bit */
108+
while ((mbox[msg.channel].sts & CHANNEL_STS_MASK));
109+
interrupt_unlock(key);
110+
}
111+
112+
static uint16_t get_chall_sts (void)
113+
{
114+
return MMIO_REG_VAL(IO_REG_MAILBOX_CHALL_STS) & CHALL_STATUS_MASK;
115+
}
116+
117+
static void mailbox_isr (void)
118+
{
119+
int i;
120+
uint32_t sts;
121+
CurieMailboxMsg msg;
122+
123+
sts = get_chall_sts();
124+
/* Get channel number */
125+
for (i = 0; i < NUM_MAILBOX_CHANNELS; ++i) {
126+
if (sts & (1 << (i * 2 + 1))) {
127+
break;
128+
}
129+
}
130+
131+
mailbox_read(i, msg);
132+
do_callback(i, msg);
133+
}
134+
135+
static void mailbox_hardware_init (void)
136+
{
137+
int i;
138+
139+
for (i = 0; i < NUM_MAILBOX_CHANNELS; ++i) {
140+
mbox[i].sts &= ~(CHANNEL_STS_BITS);
141+
}
142+
}
143+
144+
static void mailbox_interrupts_init (bool master)
145+
{
146+
interrupt_disable(SOC_MBOX_INTERRUPT);
147+
148+
/* Mask SS mailbox interrupts for all channels;
149+
* Unmasking is done by enableReceive */
150+
intmask->ss_intmask = 0xFF;
151+
152+
if (master) mailbox_hardware_init();
153+
interrupt_connect(SOC_MBOX_INTERRUPT, mailbox_isr);
154+
interrupt_enable(SOC_MBOX_INTERRUPT);
155+
}
156+
157+
void mailbox_init (bool master)
158+
{
159+
intmask = (mbox_intmask_t *)IO_REG_MAILBOX_INT_MASK;
160+
mbox = (mbox_channel_t *)IO_REG_MAILBOX_BASE;
161+
memset(callbacks, 0, sizeof(callbacks));
162+
mailbox_interrupts_init(master);
163+
}

Diff for: cores/arduino/mailbox.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef _MAILBOX_H_
2+
#define _MAILBOX_H_
3+
4+
#define NUM_MAILBOX_CHANNELS 8
5+
#define CHANNEL_DATA_WORDS 4
6+
7+
class CurieMailboxMsg {
8+
public:
9+
uint32_t data[CHANNEL_DATA_WORDS];
10+
uint32_t id;
11+
int channel = 0;
12+
};
13+
14+
void mailbox_init (bool master);
15+
void mailbox_register (int channel, void(*callback)(CurieMailboxMsg));
16+
void mailbox_unregister (int channel);
17+
void mailbox_enable_receive (int channel);
18+
void mailbox_disable_receive (int channel);
19+
void mailbox_write(CurieMailboxMsg msg);
20+
21+
#endif

Diff for: libraries/CurieMailbox/README.txt

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
CurieMailbox library for Arduino/Genuino 101
2+
3+
Overview:
4+
5+
This library provides access to the inter-processor mailbox that allows
6+
interrupt-based communication between the x86 and ARC cores contained in the
7+
Curie module (in such a transaction, the message sender is referred to as the
8+
"source" processor, and the recipient as the destination processor). Note that
9+
using this library to send a message to the mailbox, when there is no
10+
application running at the destination to receive it, will cause the source
11+
processor busy-wait indefinitely.
12+
13+
Message format:
14+
15+
The CurieMailbox library uses the CurieMailboxMsg class to describe a message
16+
for the mailbox. In total, a mailbox message contains 17 bytes of data that you
17+
can fill. Here's how you might populate a CurieMailboxMsg;
18+
19+
#include "CurieMailbox.h"
20+
CurieMailboxMsg msg;
21+
22+
/* ID can be any 31-bit value */
23+
msg.id = 0x7FFFFF;
24+
25+
/* Data payload is an array of 4 32-bit values */
26+
msg.data[0] = 0xDEADBEEF;
27+
msg.data[1] = 0xCAFEBABE;
28+
msg.data[2] = 0xFFFFFFFF;
29+
msg.data[3] = 0x00000000;
30+
31+
/* And the channel on which the message will be sent */
32+
msg.channel = 6;
33+
34+
API reference:
35+
36+
37+
void CurieMailbox::begin (bool master)
38+
39+
Enable interrupts for the mailbox, and optionally initialise the
40+
mailbox hardware.
41+
42+
Params:
43+
44+
bool master: flag indicating whether mailbox hardware should be initialised.
45+
The first processor to access the mailbox should do this; if in doubt, set
46+
to false (default is false, no initialisation).
47+
48+
49+
50+
void CurieMailbox::begin (void)
51+
52+
Enable interrupts for the mailbox, and do not initialise the hardware.
53+
54+
Params:
55+
56+
None.
57+
58+
59+
60+
void CurieMailbox::enableReceive (unsigned int channel)
61+
62+
Unmask interrupts for mailbox channel 'channel', allowing it to receive
63+
messages (channels can always send, only reception has to be enabled).
64+
65+
Params:
66+
67+
int channel: integer value (0-7) representing the channel to be enabled.
68+
If the passed value does not represent a valid channel, then the highest
69+
channel will be used instead.
70+
71+
72+
73+
void CurieMailbox::disableReceive (unsigned int channel)
74+
75+
Mask interrupts for mailbox channel 'channel', so that messages can no longer
76+
be received (but they can still be sent).
77+
78+
Params:
79+
80+
int channel: integer value (0-7) representing the channel to be enabled.
81+
If the passed value does not represent a valid channel, then the highest
82+
channel will be used instead.
83+
84+
85+
int CurieMailbox::available (void)
86+
87+
Returns the number of received mailbox messages available for reading.
88+
89+
Params:
90+
91+
None
92+
93+
94+
95+
void CurieMailbox::put (CurieMailboxMsg msg)
96+
97+
Writes the message 'msg' to the mailbox.
98+
99+
Params:
100+
101+
CurieMailboxMsg msg: the message to send
102+
103+
104+
105+
CurieMailboxMsg CurieMailbox::get (void)
106+
107+
Gets the most recently received unread message from the mailbox.
108+
109+
Params:
110+
111+
None.
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
ifeq ("$(strip $(CODK_DIR))", "")
2+
$(error Please set the CODK_DIR variable.)
3+
endif
4+
5+
ARDUINOSW_DIR ?= $(CODK_DIR)/arc
6+
7+
current_dir = $(shell pwd)
8+
9+
VERBOSE = true
10+
11+
LIBDIRS = $(ARDUINOSW_DIR)/corelibs/libraries/CurieMailbox/src
12+
13+
include $(ARDUINOSW_DIR)/Makefile.inc
14+
15+
all: compile
16+
17+
.DEFAULT_GOAL := all
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* CurieMailbox: Shared Counter example
3+
*
4+
* Requires sample Zephyr application CurieMailbox_SharedCounter running on x86
5+
* core (get it from https://github.com/01org/CODK-M-X86-Samples)
6+
*
7+
* This example demonstrates sharing a single integer value between the x86
8+
* and ARC core. This sketch (ARC core) starts by sending a value of 0 using
9+
* CurieMailbox.put(). This is received by the application running on the x86
10+
* core, which increments the value by 1 and sends it back via the mailbox.
11+
*
12+
* This sketch will read the reply, and again increment it by one and send
13+
* it back to the x86 core through the mailbox. In this way the count value
14+
* will increase indefinitely, with each core performing alternate increments
15+
* and using the mailbox to pass the value in between.
16+
*
17+
* Copyright (c) 2016 Intel Corporation. All rights reserved.
18+
* See the bottom of this file for the license terms.
19+
*/
20+
21+
#include "CurieMailbox.h"
22+
23+
uint32_t count = 0;
24+
25+
int sendChannel = 0; /* We'll send mailbox messages on this channel */
26+
int receiveChannel = 1; /* And receive them on this channel */
27+
28+
void setup (void) {
29+
Serial.begin(9600);
30+
31+
/* Enable the mailbox */
32+
CurieMailbox.begin();
33+
34+
/* Enable channel for receiving messages */
35+
CurieMailbox.enableReceive(receiveChannel);
36+
}
37+
38+
void loop (void) {
39+
CurieMailboxMsg outMsg; /* This will store the message we are sending */
40+
CurieMailboxMsg inMsg; /* This will store the received message */
41+
42+
delay(1000);
43+
44+
outMsg.id = 0; /* ID can be whatever you like */
45+
outMsg.data[0] = count; /* Data is an array of 4 uint32_t types */
46+
outMsg.channel = sendChannel; /* Sending this message to sendChannel */
47+
48+
CurieMailbox.put(outMsg); /* Send the message */
49+
50+
/* Wait for the response */
51+
while (CurieMailbox.available() == 0);
52+
53+
/* Read the response */
54+
inMsg = CurieMailbox.get();
55+
56+
Serial.print("Sent '" + String(outMsg.data[0]) + "' on channel ");
57+
Serial.print(String(outMsg.channel) + ", got reply '" + String(inMsg.data[0]));
58+
Serial.println("' on channel " + String(inMsg.channel));
59+
60+
/* Update our count value with the value received from mailbox */
61+
count = inMsg.data[0] + 1;
62+
}
63+
64+
/*
65+
* Copyright (c) 2016 Intel Corporation. All rights reserved.
66+
*
67+
* This library is free software; you can redistribute it and/or
68+
* modify it under the terms of the GNU Lesser General Public
69+
* License as published by the Free Software Foundation; either
70+
* version 2.1 of the License, or (at your option) any later version.
71+
*
72+
* This library is distributed in the hope that it will be useful,
73+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
74+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
75+
* Lesser General Public License for more details.
76+
*
77+
* You should have received a copy of the GNU Lesser General Public
78+
* License along with this library; if not, write to the Free Software
79+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
80+
*/

0 commit comments

Comments
 (0)