Skip to content

Instantly share code, notes, and snippets.

@jancumps
Last active August 17, 2019 14:21
Show Gist options
  • Save jancumps/ee9482dd27856c823ddcf505830dece4 to your computer and use it in GitHub Desktop.
Save jancumps/ee9482dd27856c823ddcf505830dece4 to your computer and use it in GitHub Desktop.
// Based on LAB 6: Blinking LEDs with RPMsg from Linux User Space.
// http://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs#LAB_6:_Blinking_LEDs_with_RPMsg_from_Linux_User_Space
/*
* Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <ctype.h>
#include <pru_cfg.h>
#include <pru_intc.h>
#include <rsc_types.h>
#include <pru_rpmsg.h>
#include "resource_table_0.h"
typedef struct {
// pin assignments
uint32_t pin_step;
uint32_t pin_dir;
// status
uint32_t dir;
uint32_t steps;
uint32_t clockDivider;
} motor_t;
#define MOTOR_COUNT 1U
#define PIN_STEP_MOTOR1 1U
#define PIN_DIR_MOTOR1 0U
motor_t motors[MOTOR_COUNT];
void motor_init();
bool parseArmCmd (void *data, uint16_t len);
static int opt_int_pow(int n);
volatile register uint32_t __R30;
volatile register uint32_t __R31;
/* Host-0 Interrupt sets bit 30 in register R31 */
#define HOST_INT ((uint32_t) 1 << 30)
/* The PRU-ICSS system events used for RPMsg are defined in the Linux device tree
* PRU0 uses system event 16 (To ARM) and 17 (From ARM)
* PRU1 uses system event 18 (To ARM) and 19 (From ARM)
*/
#define TO_ARM_HOST 16
#define FROM_ARM_HOST 17
/*
* Using the name 'rpmsg-pru' will probe the rpmsg_pru driver found
* at linux-x.y.z/drivers/rpmsg/rpmsg_pru.c
*/
#define CHAN_NAME "rpmsg-pru"
#define CHAN_DESC "Channel 30"
#define CHAN_PORT 30
/*
* Used to make sure the Linux drivers are ready for RPMsg communication
* Found at linux-x.y.z/include/uapi/linux/virtio_config.h
*/
#define VIRTIO_CONFIG_S_DRIVER_OK 4
uint8_t payload[RPMSG_MESSAGE_SIZE];
/*
* main.c
*/
void main(void)
{
struct pru_rpmsg_transport transport;
uint16_t src, dst, len;
volatile uint8_t *status;
__R30 = 0x0;
/* Allow OCP master port access by the PRU so the PRU can read external memories */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
/* Clear the status of the PRU-ICSS system event that the ARM will use to 'kick' us */
CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
/* Make sure the Linux drivers are ready for RPMsg communication */
status = &resourceTable.rpmsg_vdev.status;
while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK));
/* Initialize the RPMsg transport structure */
pru_rpmsg_init(&transport, &resourceTable.rpmsg_vring0, &resourceTable.rpmsg_vring1, TO_ARM_HOST, FROM_ARM_HOST);
motor_init();
/* Create the RPMsg channel between the PRU and ARM user space using the transport structure. */
while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, CHAN_NAME, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS);
while (1) {
/* Check bit 30 of register R31 to see if the ARM has kicked us */
if (__R31 & HOST_INT) {
/* Clear the event status */
CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
/* Receive all available messages, multiple messages can be sent per kick */
while (pru_rpmsg_receive(&transport, &src, &dst, payload, &len) == PRU_RPMSG_SUCCESS) {
if (parseArmCmd(payload, len)) {
if (motors[0].dir) {
__R30 |= 1UL << motors[0].pin_dir;
} else {
__R30 &= ~(1UL << motors[0].pin_dir);
}
int delay = 60000;
int i;
// toggle STEP twice the pulse count (a pulse is two toggles)
for (i = 0; i < motors[0].steps * 2; i++) {
__R30 ^= 1UL << motors[0].pin_step; // can be optimised if I constant the right operator
// __delay_cycles(300000); // Intrinsic method delay
int j;
for (j = 0; j < delay; j++) {
}
}
}
}
}
}
}
void motor_init() {
// todo this should become parameterised.
// initialise motor array
motors[0].pin_dir = PIN_DIR_MOTOR1;
motors[0].pin_step = PIN_STEP_MOTOR1;
motors[0].dir = 0U;
// set STEP low
__R30 &= ~motors[0].pin_step;
// set dir to inital dir
__R30 &= ~motors[0].dir << motors[0].pin_dir;
}
bool parseArmCmd (void *data, uint16_t len) {
if (len < 2) { // at least directory and 1 bit of counts
return false;
}
// fist position is direction. If '0', then clear DIR bit, else set dir bit
if (payload[0] == '0') {
// __R30 &= ~(1UL << DIR);
motors[0].dir = 0U;
} else {
// __R30 |= 1UL << DIR;
motors[0].dir = 1U;
}
// get the number of pulses
int i;
uint32_t pulses = 0U;
for (i = 1; i < len; i++) {
if (isdigit(payload[i])) {
pulses += ((payload[i] - '0') * opt_int_pow(len - 2 - i));
}
}
motors[0].steps = pulses;
return true;
}
static int opt_int_pow(int n) {
int r = 1;
const int x = 10;
while (n) {
if (n & 1) {
r *= x;
n--;
}
else {
r *= x * x;
n -= 2;
}
}
return r;
}
@jancumps
Copy link
Author

jancumps commented Aug 17, 2019

version 1 works
version 2 is the start of refactoring for timer and multiple motors
version 5 with motor init and ARM parameter parsing factored out of the main flow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment