The purpose of this project was to add features to Adam Taylor's MiniZed tutorial as a challenge during the motor control seminar. Since we were only given 2 weeks to complete the challenge, there was much to do in so little time.
I looked around the lab for some unique gadget to connect the MiniZed to, and then I saw ol' Bob the robot from Element14. I've got a few of them from various grab bags and event swag boxes, so one will be sacrificed for this project.
Enclosure:
I've included my MiniZed 3D print.stl file for my enclosure.
Mecha-man:
First, Bob had to be disassembled to determine how to attach a motor to the wind-up mechanism.
I saved the main eccentric shaft and gear and drilled it to fit the larger motor shaft.
Then I used some scrap copper to make a motor mount by soldering it around the motor body and drilling a screw hole.
Software:
I didn't make too many changes to the software, just fixed up some syntax errors in the menu, added code to reverse the motor, and slowed down the motor a bit so Bob didn't self-destruct.
//Modified by RSC 2/2/2020
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpiops.h"
#include "sleep.h"
#include "xil_exception.h"
#include "xttcps.h"
#include "xscugic.h"
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID
#define TICK_TIMER_FREQ_HZ 100
#define TTC_TICK_DEVICE_ID XPAR_XTTCPS_0_DEVICE_ID
#define TTC_TICK_INTR_ID XPAR_XTTCPS_0_INTR
int direction=1; //motor direction CW or CCW
int speed=0;
static void TickHandler(void *CallBackRef);
int SetupTicker(XTtcPs *TtcPsInst,u16 DeviceID,u16 TtcTickIntrID,XScuGic *InterruptController);
static int SetupInterruptSystem(u16 IntcDeviceID,XScuGic *IntcInstancePtr);
int SetupTimer(u16 DeviceID,XTtcPs *TtcPsInst);
void set_pwm(u32 cycle);
void display_menu();
typedef struct {
u32 OutputHz; /* Output frequency */
XInterval Interval; /* Interval value */
u8 Prescaler; /* Prescaler value */
u16 Options; /* Option settings */
} TmrCntrSetup;
XGpioPs Gpio;
XGpioPs_Config *ConfigPtr;
XTtcPs_Config *TtcConfig;
XTtcPs ttcTimer;
TmrCntrSetup *TimerSetup;
XScuGic InterruptController; /* Interrupt controller instance */
XTtcPs TtcPsInst;
u32 MatchValue;
static TmrCntrSetup SettingsTable={TICK_TIMER_FREQ_HZ, 0, 0, 0};
int main()
{
u8 DutyCycle;
char key_input;
init_platform();
TmrCntrSetup SettingsTable= {TICK_TIMER_FREQ_HZ, 0, 0, 0};
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
XGpioPs_SetDirectionPin(&Gpio, 54, 1);
XGpioPs_SetOutputEnablePin(&Gpio, 54, 1);
XGpioPs_WritePin(&Gpio, 54, direction);
printf("www.adiuvoengineering.com\n\r");
printf("DC Motor Control Example\n\r");
SetupInterruptSystem(INTC_DEVICE_ID, &InterruptController);
SetupTicker(&ttcTimer,TTC_TICK_DEVICE_ID,TTC_TICK_INTR_ID,&InterruptController);
while(1){
display_menu();
if (direction==1)
printf("Direction = CW\n");
else if (direction==0)
printf("Direction = CCW\n");
printf("Speed = %d%%\n",speed);
read(1, (char*)&key_input, 1);
switch (key_input) {
case '0': // toggle direction
set_pwm(0);
speed=0;
if (direction==0x1)
direction=0;
else
direction=1;
XGpioPs_WritePin(&Gpio, 54, direction);
break;
case '1': //stop
set_pwm(0);
break;
case '2': //5%
DutyCycle = 5;
set_pwm(DutyCycle);
speed=DutyCycle;
break;
case '3': //10%
DutyCycle = 10;
set_pwm(DutyCycle);
speed=DutyCycle;
break;
case '4': //15%
DutyCycle = 15;
set_pwm(DutyCycle);
speed=DutyCycle;
break;
case '5': //20%
DutyCycle = 20;
set_pwm(DutyCycle);
speed=DutyCycle;
break;
case '6': //25%
DutyCycle = 25;
set_pwm(DutyCycle);
speed=DutyCycle;
break;
case '7': //30%
DutyCycle = 30;
set_pwm(DutyCycle);
speed=DutyCycle;
break;
}
}
cleanup_platform();
return 0;
}
void display_menu()
{
//Clear the screen
printf("\033[2J");
//Display the main menu
printf("*******************************************\n");
printf("**** www.adiuvoengineering.com ****\n");
printf("**** Motor Control Example ****\n");
printf("**** Modified for Mecha-Bob ****\n");
printf("**** by RSC 2/2/2020 ****\n");
printf("*******************************************\n");
printf("\n");
printf(" MM10 Motor Control \n");
printf("------------------------------------------\n");
printf("\n");
printf("Select a Speed:\n");
printf(" (0) - Toggle Direction\n");
printf(" (1) - Stop\n");
printf(" (2) - 5%%\n");
printf(" (3) - 10%%\n");
printf(" (4) - 15%%\n");
printf(" (5) - 20%%\n");
printf(" (6) - 25%%\n");
printf(" (7) - 30%%\n");
printf("\n");
}
void set_pwm(u32 cycle)
{
u32 MatchValue;
MatchValue = (TimerSetup->Interval * cycle) / 100;
XTtcPs_SetMatchValue(&ttcTimer, 0, MatchValue);
}
int SetupTicker(XTtcPs *TtcPsInst,u16 DeviceID,u16 TtcTickIntrID,XScuGic *InterruptController)
{
int Status;
TmrCntrSetup *TimerSetup;
XTtcPs *TtcPsTick;
TimerSetup = &SettingsTable;
TimerSetup->Options |= (XTTCPS_OPTION_INTERVAL_MODE |
XTTCPS_OPTION_MATCH_MODE | XTTCPS_OPTION_WAVE_POLARITY);
Status = SetupTimer(DeviceID,TtcPsInst);
if(Status != XST_SUCCESS) {
return Status;
}
TtcPsTick = TtcPsInst;
Status = XScuGic_Connect(InterruptController, TtcTickIntrID,
(Xil_InterruptHandler)TickHandler, (void *)TtcPsTick);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XScuGic_Enable(InterruptController, TtcTickIntrID);
XTtcPs_EnableInterrupts(TtcPsTick, XTTCPS_IXR_INTERVAL_MASK);
XTtcPs_Start(TtcPsTick);
return Status;
}
static int SetupInterruptSystem(u16 IntcDeviceID,XScuGic *IntcInstancePtr)
{
int Status;
XScuGic_Config *IntcConfig;
IntcConfig = XScuGic_LookupConfig(IntcDeviceID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler) XScuGic_InterruptHandler,
IntcInstancePtr);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
int SetupTimer(u16 DeviceID,XTtcPs *TtcPsInst)
{
int Status;
XTtcPs_Config *Config;
XTtcPs *Timer;
TmrCntrSetup *TimerSetup;
TimerSetup = &SettingsTable;
Timer = TtcPsInst;
Config = XTtcPs_LookupConfig(DeviceID);
if (NULL == Config) {
return XST_FAILURE;
}
Status = XTtcPs_CfgInitialize(Timer, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
XTtcPs_SetOptions(Timer, TimerSetup->Options);
XTtcPs_CalcIntervalFromFreq(Timer, TimerSetup->OutputHz,
&(TimerSetup->Interval), &(TimerSetup->Prescaler));
XTtcPs_SetInterval(Timer, TimerSetup->Interval);
XTtcPs_SetPrescaler(Timer, TimerSetup->Prescaler);
return XST_SUCCESS;
}
static void TickHandler(void *CallBackRef)
{
u32 StatusEvent;
/*
* Read the interrupt status, then write it back to clear the interrupt.
*/
StatusEvent = XTtcPs_GetInterruptStatus((XTtcPs *)CallBackRef);
XTtcPs_ClearInterruptStatus((XTtcPs *)CallBackRef, StatusEvent);
//printf("timer\n\r");
/*update the flag if interrupt has been occurred*/
//UpdateFlag = TRUE;
}
Here's Bob!
Comments