Skip to content

Commit 2bfc4f3

Browse files
committed
evb-pru0: implement tachometer
copied from ev3-pru1 and modified for BeagleBone
1 parent b21e26b commit 2bfc4f3

File tree

6 files changed

+414
-124
lines changed

6 files changed

+414
-124
lines changed

evb-pru0/.cproject

Lines changed: 58 additions & 46 deletions
Large diffs are not rendered by default.

evb-pru0/.project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<name>evb-pru0</name>
44
<comment></comment>
55
<projects>
6+
<project>rpmsg_lib</project>
67
</projects>
78
<buildSpec>
89
<buildCommand>

evb-pru0/main.c

Lines changed: 207 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
2+
* Copyright (C) 2018 David Lechner <david@lechnology.com>
33
*
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -31,9 +31,213 @@
3131
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3232
*/
3333

34+
#include <stdbool.h>
3435
#include <stdint.h>
35-
#include "resource_table_empty.h"
36+
#include <stdio.h>
37+
38+
#include <rsc_types.h>
39+
40+
#include <pru_cfg.h>
41+
#include <pru_ctrl.h>
42+
#include <pru_intc.h>
43+
#include <pru_rpmsg.h>
44+
45+
#include <sys_gpio.h>
46+
#include <sys_timer_1ms.h>
47+
48+
#include "resource_table.h"
49+
50+
/* from Linux */
51+
52+
#define EV3_PRU_TACHO_RING_BUF_SIZE 256 /* must be power of 2! */
53+
54+
enum ev3_pru_tacho_msg_type {
55+
/* Host >< PRU: request memory map address of ring buffer data */
56+
EV3_PRU_TACHO_MSG_DATA_ADDR,
57+
};
58+
59+
struct ev3_pru_tacho_msg {
60+
uint32_t type;
61+
uint32_t value;
62+
};
63+
64+
enum ev3_pru_tacho {
65+
EV3_PRU_TACHO_A,
66+
EV3_PRU_TACHO_B,
67+
EV3_PRU_TACHO_C,
68+
EV3_PRU_TACHO_D,
69+
NUM_EV3_PRU_TACHO
70+
};
71+
72+
struct ev3_pru_tacho_remote_data {
73+
uint32_t position[NUM_EV3_PRU_TACHO][EV3_PRU_TACHO_RING_BUF_SIZE];
74+
uint32_t timestamp[NUM_EV3_PRU_TACHO][EV3_PRU_TACHO_RING_BUF_SIZE];
75+
uint32_t head[NUM_EV3_PRU_TACHO];
76+
};
77+
78+
/* end Linux */
79+
80+
enum direction {
81+
REVERSE = -1,
82+
UNKNOWN = 0,
83+
FORWARD = 1
84+
};
85+
86+
/* Host-0 Interrupt sets bit 30 in register R31 */
87+
#define HOST_INT ((uint32_t) 1 << 30)
88+
89+
/* The PRU-ICSS system events used for RPMsg are defined in the Linux device tree
90+
* PRU0 uses system event 16 (To ARM) and 17 (From ARM)
91+
* PRU1 uses system event 18 (To ARM) and 19 (From ARM)
92+
*/
93+
#define TO_ARM_HOST 16
94+
#define FROM_ARM_HOST 17
95+
96+
#define PRU_GLOBAL_BASE_ADDR 0x4a300000
97+
#define PRU_SRAM __far __attribute__((cregister("PRU_SHAREDMEM", far)))
98+
99+
/*
100+
* Used to make sure the Linux drivers are ready for RPMsg communication
101+
* Found at linux-x.y.z/include/uapi/linux/virtio_config.h
102+
*/
103+
#define VIRTIO_CONFIG_S_DRIVER_OK 4
104+
105+
volatile register uint32_t __R31;
106+
107+
#if defined(PLAT_EVB)
108+
109+
#define INTA GPIO2.GPIO_DATAIN_bit.DATAIN4
110+
#define INTB GPIO0.GPIO_DATAIN_bit.DATAIN26
111+
#define INTC GPIO0.GPIO_DATAIN_bit.DATAIN27
112+
#define INTD GPIO2.GPIO_DATAIN_bit.DATAIN11
113+
114+
#define DIRA GPIO2.GPIO_DATAIN_bit.DATAIN3
115+
#define DIRB GPIO1.GPIO_DATAIN_bit.DATAIN12
116+
#define DIRC GPIO1.GPIO_DATAIN_bit.DATAIN31
117+
#define DIRD GPIO2.GPIO_DATAIN_bit.DATAIN9
118+
119+
#elif defined(PLAT_QUEST)
120+
121+
#define INTA GPIO2.GPIO_DATAIN_bit.DATAIN4
122+
#define INTB GPIO0.GPIO_DATAIN_bit.DATAIN26
123+
#define INTC GPIO0.GPIO_DATAIN_bit.DATAIN27
124+
#define INTD GPIO2.GPIO_DATAIN_bit.DATAIN12
125+
126+
#define DIRA GPIO2.GPIO_DATAIN_bit.DATAIN3
127+
#define DIRB GPIO1.GPIO_DATAIN_bit.DATAIN12
128+
#define DIRC GPIO1.GPIO_DATAIN_bit.DATAIN31
129+
#define DIRD GPIO2.GPIO_DATAIN_bit.DATAIN13
130+
131+
#else
132+
#error Must define PLAT_xyz
133+
#endif
134+
135+
#define TACHO_STATE(x) ((INT##x << 1) | DIR##x)
136+
137+
static uint8_t tacho_state[NUM_EV3_PRU_TACHO];
138+
static uint32_t tacho_prev_timestamp[NUM_EV3_PRU_TACHO];
139+
static uint32_t tacho_counts[NUM_EV3_PRU_TACHO];
140+
141+
static uint8_t payload[RPMSG_BUF_SIZE];
142+
static PRU_SRAM struct ev3_pru_tacho_remote_data remote_data;
143+
144+
static void update_tacho_state(enum ev3_pru_tacho idx, uint8_t new_state)
145+
{
146+
uint8_t current_state = tacho_state[idx] & 0x3;
147+
enum direction new_dir = UNKNOWN;
148+
uint32_t now, elapsed;
149+
150+
switch (current_state) {
151+
case 0x0:
152+
if (new_state == 0x1) {
153+
new_dir = FORWARD;
154+
} else if (new_state == 0x2) {
155+
new_dir = REVERSE;
156+
}
157+
break;
158+
159+
case 0x1:
160+
if (new_state == 0x3) {
161+
new_dir = FORWARD;
162+
} else if (new_state == 0x0) {
163+
new_dir = REVERSE;
164+
}
165+
break;
166+
167+
case 0x3:
168+
if (new_state == 0x2) {
169+
new_dir = FORWARD;
170+
} else if (new_state == 0x1) {
171+
new_dir = REVERSE;
172+
}
173+
break;
174+
175+
case 0x2:
176+
if (new_state == 0x0) {
177+
new_dir = FORWARD;
178+
} else if (new_state == 0x3) {
179+
new_dir = REVERSE;
180+
}
181+
break;
182+
}
183+
184+
tacho_state[idx] = new_state;
185+
tacho_counts[idx] += new_dir;
186+
187+
now = DMTIMER1_1MS.TCRR;
188+
elapsed = now - tacho_prev_timestamp[idx];
189+
190+
// if there was a change in count or if count hasn't changed for 50ms
191+
if (new_dir || elapsed > (50 * 1000000 * 3 / 125)) {
192+
uint32_t new_head = (remote_data.head[idx] + 1) & (EV3_PRU_TACHO_RING_BUF_SIZE - 1);
193+
194+
tacho_prev_timestamp[idx] = now;
195+
196+
remote_data.position[idx][new_head] = tacho_counts[idx];
197+
remote_data.timestamp[idx][new_head] = now;
198+
remote_data.head[idx] = new_head;
199+
}
200+
}
36201

37202
int main(void) {
38-
__halt();
203+
volatile uint8_t *status;
204+
struct pru_rpmsg_transport transport;
205+
uint16_t src, dst, len;
206+
207+
// Clear the status of the PRU-system event that the ARM will use to 'kick' us
208+
CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
209+
210+
// Wait until Linux gives us the OK that the driver is loaded
211+
status = &resource_table.rpmsg_vdev.status;
212+
while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK));
213+
214+
pru_virtqueue_init(&transport.virtqueue0, &resource_table.rpmsg_vring0, TO_ARM_HOST, FROM_ARM_HOST);
215+
pru_virtqueue_init(&transport.virtqueue1, &resource_table.rpmsg_vring1, TO_ARM_HOST, FROM_ARM_HOST);
216+
217+
while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, "ev3-tacho-rpmsg", "", 0) != PRU_RPMSG_SUCCESS);
218+
219+
while (true) {
220+
// wait for the ARM to kick us
221+
while (!(__R31 & HOST_INT)) {
222+
update_tacho_state(EV3_PRU_TACHO_A, TACHO_STATE(A));
223+
update_tacho_state(EV3_PRU_TACHO_B, TACHO_STATE(B));
224+
update_tacho_state(EV3_PRU_TACHO_C, TACHO_STATE(C));
225+
update_tacho_state(EV3_PRU_TACHO_D, TACHO_STATE(D));
226+
}
227+
228+
// clear the interrupt
229+
CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
230+
231+
// Receive all available messages, multiple messages can be sent per kick
232+
while (pru_rpmsg_receive(&transport, &src, &dst, payload, &len) == PRU_RPMSG_SUCCESS) {
233+
struct ev3_pru_tacho_msg *msg = (void *)payload;
234+
235+
switch (msg->type) {
236+
case EV3_PRU_TACHO_MSG_DATA_ADDR:
237+
msg->value = PRU_GLOBAL_BASE_ADDR + (uint32_t)&remote_data;
238+
pru_rpmsg_send(&transport, dst, src, msg, sizeof(*msg));
239+
break;
240+
}
241+
}
242+
}
39243
}

evb-pru0/resource_table.h

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
*
11+
* * Redistributions in binary form must reproduce the above copyright
12+
* notice, this list of conditions and the following disclaimer in the
13+
* documentation and/or other materials provided with the
14+
* distribution.
15+
*
16+
* * Neither the name of Texas Instruments Incorporated nor the names of
17+
* its contributors may be used to endorse or promote products derived
18+
* from this software without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
33+
#ifndef _RSC_TABLE_PRU_H_
34+
#define _RSC_TABLE_PRU_H_
35+
36+
#include <stddef.h>
37+
#include <rsc_types.h>
38+
#include "pru_virtio_ids.h"
39+
40+
/*
41+
* Sizes of the virtqueues (expressed in number of buffers supported,
42+
* and must be power of 2)
43+
*/
44+
#define PRU_RPMSG_VQ0_SIZE 16
45+
#define PRU_RPMSG_VQ1_SIZE 16
46+
47+
/*
48+
* The feature bitmap for virtio rpmsg
49+
*/
50+
#define VIRTIO_RPMSG_F_NS 0 //name service notifications
51+
52+
/* This firmware supports name service notifications as one of its features */
53+
#define RPMSG_PRU_C0_FEATURES (1 << VIRTIO_RPMSG_F_NS)
54+
55+
/* Definition for unused interrupts */
56+
#define HOST_UNUSED 255
57+
58+
/* Number of entries in the table */
59+
#define NUM_RESORUCES 2
60+
61+
/* Mapping sysevts to a channel. Each pair contains a sysevt, channel. */
62+
struct ch_map pru_intc_map[] = {
63+
{ .evt = 16, .ch = 2 },
64+
{ .evt = 17, .ch = 0 },
65+
};
66+
67+
struct pru0_resource_table {
68+
struct resource_table base;
69+
70+
uint32_t offset[NUM_RESORUCES];
71+
72+
/* rpmsg vdev entry */
73+
struct fw_rsc_vdev rpmsg_vdev;
74+
struct fw_rsc_vdev_vring rpmsg_vring0;
75+
struct fw_rsc_vdev_vring rpmsg_vring1;
76+
77+
/* intc definition */
78+
struct fw_rsc_custom pru_ints;
79+
};
80+
81+
#pragma DATA_SECTION(resource_table, ".resource_table")
82+
#pragma RETAIN(resource_table)
83+
struct pru0_resource_table resource_table = {
84+
.base = {
85+
.ver = 1, /* only version 1 is supported by the current driver */
86+
.num = NUM_RESORUCES,
87+
.reserved = { 0, 0 }, /* must be zero */
88+
},
89+
/* offsets to entries */
90+
.offset = {
91+
offsetof(struct pru0_resource_table, rpmsg_vdev),
92+
offsetof(struct pru0_resource_table, pru_ints),
93+
},
94+
95+
/* rpmsg vdev entry */
96+
.rpmsg_vdev = {
97+
.type = TYPE_VDEV,
98+
.id = VIRTIO_ID_RPMSG,
99+
.notifyid = 0,
100+
.dfeatures = RPMSG_PRU_C0_FEATURES,
101+
.gfeatures = 0,
102+
.config_len = 0,
103+
.status = 0,
104+
.num_of_vrings = 2, // only two is supported
105+
.reserved = { 0, 0 },
106+
},
107+
/* the two vrings */
108+
.rpmsg_vring0 = {
109+
.da = 0, //will be populated by host, can't pass it in
110+
.align = 16, //(bytes),
111+
.num = PRU_RPMSG_VQ0_SIZE, //num of descriptors
112+
.notifyid = 0, //will be populated, can't pass right now
113+
.reserved = 0,
114+
},
115+
.rpmsg_vring1 = {
116+
.da = 0, //will be populated by host, can't pass it in
117+
.align = 16, //(bytes),
118+
.num = PRU_RPMSG_VQ1_SIZE, //num of descriptors
119+
.notifyid = 0, //will be populated, can't pass right now
120+
.reserved = 0,
121+
},
122+
123+
.pru_ints = {
124+
.type = TYPE_POSTLOAD_VENDOR,
125+
.sub_type = TYPE_PRU_INTS,
126+
.rsc_size = sizeof(struct fw_rsc_custom_ints),
127+
.rsc.pru_ints = {
128+
.version = 0x0000,
129+
.channel_host = {
130+
0,
131+
HOST_UNUSED,
132+
2,
133+
HOST_UNUSED,
134+
HOST_UNUSED,
135+
HOST_UNUSED,
136+
HOST_UNUSED,
137+
HOST_UNUSED,
138+
HOST_UNUSED,
139+
HOST_UNUSED,
140+
},
141+
.num_evts = (sizeof(pru_intc_map) / sizeof(struct ch_map)),
142+
.event_channel = pru_intc_map,
143+
},
144+
},
145+
};
146+
147+
#endif /* _RSC_TABLE_PRU_H_ */

0 commit comments

Comments
 (0)