Open Mokutsuno opened 7 years ago
You haven't given me much information to work on, here. I would suggest you run Printipi under a debugger (like gdb
). You could interrupt it when it hangs (with Ctrl+C) and then get a stack trace by typing bt
. This might reveal if it's stuck in a loop / blocking call, etc.
One thing I would also do is check the return code of hardware_PWM
. I'm not sure which parts of the code you've edited, but you should make sure that the original hardwarescheduler.cpp isn't being compiled - it also uses DMA and might conflict with the DMA channel that pigpio's hardware_PWM
function is using.
I just dug up the documentation for hardware_PWM. It looks to me like this is calling into a separate daemon to manage the gpios. As such, if you haven't started the pigpio daemon before running printipi, it's quite possible that their code is written in a way where it stalls until the daemon is started.
Thank you for your reply.
printipi doesn't hang. printipi executes first command (G1 Y0.1 F6000 e.g.),but doesn't execute next command. It keeps outputting "[inf0] RCThermistor2Pin read timeout" during running it.
The original hardwarescheduler.cpp isn't being compiled. The pigpio daemon has been start since boot the raspberry pi 3.
I used gdb. As a result,hardware_PWM()
did not return 0. It returned -95.
I noticed that hardware_PWM(
)(pwmWrite()
) was called twice only.
First,it is called about V1_GPIO_P1_08 (probably FAN).
Second,called about V1_GPIO_P1_10 (probably HOTEND). Both return -95.
hardware_PWM(
)(pwmWrite()
) isn't called, when I input commands.
I can't understand why GPIO toggle (But as above, it doesn't work as intended). There are no functions to make PWM other than hardware_PWM(
)(pwmWrite()
) in printipi. Why?
I followed https://github.com/Wallacoloo/printipi/wiki/Adding-support-for-a-new-CPU-architecture There are "chronoclock.cpp","chronoclock.h","mitpi.cpp","mitpi.h","primitiveiopin.h" and "hardwarescheduler.cpp". under platform/rpi2 directory. "chronoclock.cpp" and "chronoclock.h" are the same as https://github.com/Wallacoloo/printipi/blob/master/src/platforms/rpi/chronoclock.cpp https://github.com/Wallacoloo/printipi/blob/master/src/platforms/rpi/chronoclock.h I changed "primitiveiopin.h" a little.
mitpi.cpp
#include "mitpi.h"
#include <sys/mman.h> //for mmap
#include <sys/time.h>
#include <time.h> //for nanosleep / usleep (if have -std=gnu99)
#include <unistd.h> //for usleep
#include <stdlib.h> //for exit
#include <cassert> //for assert
#include <fcntl.h> //for file opening
#include "common/logging.h"
#include "platforms/auto/primitiveiopin.h"
#include <pigpiod_if.h>
#include <sys/time.h>
#include "platforms/auto/chronoclock.h" //for EventClockT
namespace mitpi {
#define PI_INPUT 0
#define PI_OUTPUT 1
#define PI_LOW 0
#define PI_HIGH 1
static volatile uint32_t *gpioBaseMem = nullptr;
static volatile uint32_t *timerBaseMem = nullptr;
static volatile uint32_t *gpioPadBaseMem = nullptr;
static void assertValidPin(PinIntType pin) {
(void)pin; //unused when assertions are disabled.
//printf("%d\n",(int)pin);
assert(pin >= 0 && pin < 64);
}
bool init() {
// Connect to pigpiod
int status = pigpio_start(0, 0);
if (status < 0){ LOG("Failed \pigpio_start\n");}
return 0; //init OK
}
void makeOutput(PinIntType pin) {
assertValidPin(pin);
set_mode(pin, PI_OUTPUT);
}
void makeInput(PinIntType pin) {
assertValidPin(pin);
//set_mode(pin, PI_INPUT);
}
void setPinHigh(PinIntType pin) {
assertValidPin(pin);
gpio_write(pin, PI_HIGH); // 1 is HIGH
}
void setPinLow(PinIntType pin) {
assertValidPin(pin);
gpio_write(pin, PI_LOW); // 0 is LOW
}
void setPinState(PinIntType pin, bool state) {
state ? setPinHigh(pin) : setPinLow(pin);
}
bool readPinState(PinIntType pin) {
assertValidPin(pin);
gpio_read(pin);
}
void setPinPull(PinIntType pin, GpioPull pull) {
assertValidPin(pin);
set_pull_up_down(pin, pull);
}
void setPadProperties(uint32_t flags, int bank) {
}
void usleep(unsigned int us) {
//explicitly exposed to allow users of the library access to a usleep function
::usleep(us);
}
struct timeval sysTimeMicro;
uint64_t readSysTime() {
gettimeofday(&sysTimeMicro,NULL);
return ((uint64_t)(sysTimeMicro.tv_usec));
}
}
mitpi.h
#ifndef PLATFORMS_RPI_MITPI_H
#define PLATFORMS_RPI_MITPI_H
//for uint32_t
#include <sys/time.h>
#include <stdint.h>
/*
* Mitpi is a small library used for interfacing with the Raspberry Pi's peripherals, including GPIO and timers,
* licensed under the extremely permissive MIT license.
*
* Please note that most of its features require superuser priviledges, so you may have to launch any executable which uses this library with `sudo'
*/
namespace mitpi {
//Map physical pin locations to logical pin ids used by the processor
enum GpioPin {
//There are 2 board revisions (and now the model A+/B+), which have slightly different I/O wiring.
//P1 header (2x13 pins) for version 1 (i.e. before Sept 2012:
//looking down at the board with the P1 header in the upper right,
//The upper-left pin is P1_01,
//The upper-right pin is P1_02 (so, odds are left, evens are right)
//numbering increases as you go vertically down
V1_GPIO_P1_03 = 0, //(i.e., physical pin #3 is addressed in software as #0)
V1_GPIO_P1_05 = 1,
V1_GPIO_P1_07 = 4,
V1_GPIO_P1_08 = 14,
V1_GPIO_P1_10 = 15,
V1_GPIO_P1_11 = 17,
V1_GPIO_P1_12 = 18,
V1_GPIO_P1_13 = 21,
V1_GPIO_P1_15 = 22,
V1_GPIO_P1_16 = 23,
V1_GPIO_P1_18 = 24,
V1_GPIO_P1_19 = 10,
V1_GPIO_P1_21 = 9,
V1_GPIO_P1_22 = 25,
V1_GPIO_P1_23 = 11,
V1_GPIO_P1_24 = 8,
V1_GPIO_P1_26 = 7,
//The P1 header for revision 2:
//same physical numbering as before
V2_GPIO_P1_03 = 2,
V2_GPIO_P1_05 = 3,
V2_GPIO_P1_07 = 4,
V2_GPIO_P1_08 = 14,
V2_GPIO_P1_10 = 15,
V2_GPIO_P1_11 = 17,
V2_GPIO_P1_12 = 18,
V2_GPIO_P1_13 = 27,
V2_GPIO_P1_15 = 22,
V2_GPIO_P1_16 = 23,
V2_GPIO_P1_18 = 24,
V2_GPIO_P1_19 = 10,
V2_GPIO_P1_21 = 9,
V2_GPIO_P1_22 = 25,
V2_GPIO_P1_23 = 11,
V2_GPIO_P1_24 = 8,
V2_GPIO_P1_26 = 7,
//Revision 2 has another 2x4 header called 'P5'.
//This doesn't have any pins soldered on by default, so (trivial) physical modification is required to use them
//Physical numbering is ordered ... how?
V2_GPIO_P5_03 = 28,
V2_GPIO_P5_04 = 29,
V2_GPIO_P5_05 = 30,
V2_GPIO_P5_06 = 31,
//The addition of the model A+ and B+ brought a 40-pin GPIO header.
//The first 26 pins are identical to the model A/B Revision 2, with the latter 14 exposing additional GPIOs
PLUS_GPIO_P1_03 = 2,
PLUS_GPIO_P1_05 = 3,
PLUS_GPIO_P1_07 = 4,
PLUS_GPIO_P1_08 = 14,
PLUS_GPIO_P1_10 = 15,
PLUS_GPIO_P1_11 = 17,
PLUS_GPIO_P1_12 = 18,
PLUS_GPIO_P1_13 = 27,
PLUS_GPIO_P1_15 = 22,
PLUS_GPIO_P1_16 = 23,
PLUS_GPIO_P1_18 = 24,
PLUS_GPIO_P1_19 = 10,
PLUS_GPIO_P1_21 = 9,
PLUS_GPIO_P1_22 = 25,
PLUS_GPIO_P1_23 = 11,
PLUS_GPIO_P1_24 = 8,
PLUS_GPIO_P1_26 = 7,
PLUS_GPIO_P1_29 = 5,
PLUS_GPIO_P1_31 = 6,
PLUS_GPIO_P1_32 = 12,
PLUS_GPIO_P1_33 = 13,
PLUS_GPIO_P1_35 = 19,
PLUS_GPIO_P1_36 = 16,
PLUS_GPIO_P1_37 = 26,
PLUS_GPIO_P1_38 = 20,
PLUS_GPIO_P1_40 = 21,
NULL_GPIO_PIN = 127,
};
//Internal pull-up / down resistors
enum GpioPull {
GPIOPULL_NONE = 0,
GPIOPULL_DOWN = 1,
GPIOPULL_UP = 2,
};
//Each bank of pins can be set to have different drive strengths, hysteresis and slew.
//pass a bitwise-or'd collection of flags to <setPadProperties>
enum GpioPadProperties {
//Per-pin drive strength. Defaults to 8 mA at boot.
//Note: avoid drawing a total of > 50 mA across ALL gpio pins / 3v3 supply
PAD_DRIVE_2MA = 0,
PAD_DRIVE_4MA = 1,
PAD_DRIVE_6MA = 2,
PAD_DRIVE_8MA = 3,
PAD_DRIVE_10MA = 4,
PAD_DRIVE_12MA = 5,
PAD_DRIVE_14MA = 6,
PAD_DRIVE_16MA = 7,
//Hysteresis settings:
PAD_HYSTERESIS_DIS = 0,
PAD_HYSTERESIS_EN = (1 << 3),
//Slew rate limit
//From Wikipedia: Slew rate is defined as the maximum rate of change of output voltage per unit of time and is expressed as volt per second.
PAD_SLEW_LIMIT = 0,
PAD_SLEW_NO_LIMIT = (1 << 4),
};
typedef unsigned int PinIntType;
bool init();
void makeOutput(PinIntType pin);
void makeInput(PinIntType pin);
void setPinHigh(PinIntType pin);
void setPinLow(PinIntType pin);
void setPinState(PinIntType pin, bool state);
bool readPinState(PinIntType pin);
void setPinPull(PinIntType pin, GpioPull pull);
//Set the drive strength, hysteresis and slew limits for a set of pins.
//@flags bitwise-or of GpioPadProperties flags
//@bank 0 for pins 0-27, 1 -> pins 28-45, 2 -> pins 46-53
void setPadProperties(uint32_t flags, int bank);
void usleep(unsigned int us);
uint64_t readSysTime();
struct InitMitpiType {
inline InitMitpiType() {
init();
}
};
}
#endif
hardwarescheduler.h
#ifndef PLATFORMS_GENERIC_HARDWARESCHEDULER_H
#define PLATFORMS_GENERIC_HARDWARESCHEDULER_H
#include <cassert> //for assert
#include "platforms/auto/chronoclock.h" //for EventClockT
#include "platforms/auto/primitiveiopin.h"
#include "schedulerbase.h" //for OnIdleCpuIntervalT (cannot forward-declare an enum)
#include "common/logging.h"
//forward declare for class defined in outputevent.h
class OutputEvent;
namespace plat {
namespace rpi2 {
struct HardwareScheduler {
//add this event to the hardware queue, waiting until schedTime(evt.time()) if necessary
inline void queue(OutputEvent evt) {
evt.primitiveIoPin().digitalWrite(evt.state());
}
//Set the given pin to a pwm duty-cycle of `ratio` using a maximum period of maxPeriod (irrelevant if using PCM algorithm).
//E.g. queuePwm(5, 0.4) sets pin #5 to a 40% duty cycle.
inline void queuePwm(const PrimitiveIoPin &pin, float ratio, float idealPeriod) {
// plat::rpi2::PrimitiveIoPin::queuePwmWrite(&pin, ratio, idealPeriod);
}
//If an event needs to occur at evtTime, this function should return the earliest time at which it can be scheduled.
inline EventClockT::time_point schedTime(EventClockT::time_point evtTime) const {
return evtTime;
}
//Can be used to perform routine resource management when there's free cpu.
//Avoid spending more than a few hundred microseconds in this function, or event scheduling might be impacted
//@return true if we request more cpu time.
inline bool onIdleCpu(OnIdleCpuIntervalT interval) {
(void)interval; //unused
return false; //no more cpu needed
}
};
}
}
#endif
primitiveiopin.h
#ifndef PLATFORMS_RPI_PRIMITIVEIOPIN_H
#define PLATFORMS_RPI_PRIMITIVEIOPIN_H
#include <cassert>
#include <stdio.h>
#include "mitpi.h" //for GpioPin
//#include "hardwarescheduler.h" //for ability to schedule PWM
#include "platforms/auto/chronoclock.h" //for EventClockT.
//for MAX_RPI_PIN_ID
#include "compileflags.h"
#include <pigpiod_if.h>
namespace plat {
namespace rpi2 {
class PrimitiveIoPin {
//logical index of this pin (0-53, I believe)
mitpi::GpioPin pinIdx;
public:
//@return a pin with an invalid output
//
//Note that it is undefined to call any function on a null pin except for <isNull> and <id>.
inline static PrimitiveIoPin null() {
return PrimitiveIoPin(mitpi::NULL_GPIO_PIN);
}
//@return true if the pin is equal to the one constructed by the <null> function.
inline bool isNull() const {
return pinIdx == mitpi::NULL_GPIO_PIN;
}
//@pinIdx *logical* index of the pin
//@pullUpDown direct this pin to either pull up to 3.3v, down to gnd, or no pull at all.
//Note that this pull direction will be applied **even when operating as an output pin**.
// The rpi's pull resistors preserve state across reboots.
// This makes it so that when the Pi resets, its pins will still be in a defined state (no runaway heater while the Pi is still booting)
// Of course, it's still a VERY GOOD IDEA to use hardware pull resistors as well.
//**Also note:** @pullUpDown acts the same regardless of the <IoPin>'s read/write inversions.
inline PrimitiveIoPin(mitpi::GpioPin pinIdx, mitpi::GpioPull pullUpDown = mitpi::GPIOPULL_NONE)
: pinIdx(pinIdx) {
assert((pinIdx == mitpi::NULL_GPIO_PIN || pinIdx <= MAX_RPI_PIN_ID) && "Make sure to appropriately set MAX_RPI_PIN_ID (see compileflags.h) or else some pins might not behave correctly");
if (pinIdx != mitpi::NULL_GPIO_PIN) {
mitpi::init();
//we CANNOT set the pin pull of a null gpio pin
mitpi::setPinPull(pinIdx, pullUpDown);
}
}
//@return the logical index of the pin (for use with other platform-specific functions)
inline mitpi::GpioPin id() const {
return pinIdx;
}
//configure the pin as an output, and set its output state
inline void makeDigitalOutput(IoLevel lev) {
mitpi::makeOutput(pinIdx);
digitalWrite(lev);
}
//configure the pin as a PWM output & set its duty cycle and period (if applicable)
inline void makePwmOutput(float duty, EventClockT::duration desiredPeriod) {
mitpi::makeOutput(pinIdx);
//mitpi::pwmWrite(pinIdx, duty, desiredPeriod);
pwmWrite(duty, desiredPeriod);
}
//configure the pin to be an input
inline void makeDigitalInput() {
mitpi::makeInput(pinIdx);
}
//read the pin's input value (must call makeDigitalInput beforehand)
inline IoLevel digitalRead() const {
return mitpi::readPinState(pinIdx);
}
//write a digital value to the pin. IoHigh = 3.3v, IoLow = 0v. Must call makeDigitalOutput beforehand
inline void digitalWrite(IoLevel lev) {
mitpi::setPinState(pinIdx, lev);
}
//set pwm duty cycle & period (if applicable). Must call makePwmOutput beforehand.
inline void pwmWrite(float duty, EventClockT::duration desiredPeriod) {
float minPeriod = std::chrono::duration_cast<std::chrono::duration<float>> (desiredPeriod).count();
int intMinPeriod = (int)minPeriod;
uint32_t intDuty = 1000000*duty;
int flag = hardware_PWM(this->id(), intMinPeriod, intDuty);
printf("%d",flag);
}
};
}
}
#endif
I succeeded being run this on rpi3 . I used pigpio. So,I made new own primitiveiopin.h , mitpi.h and mitpi.cpp ,which used pigpio.
And I got a problem. printpi toggles PWM ,when I send command of "G1 ....". It moves as intended. However, To toggle PWM isn't end,that is,printipi doesn't move on next command. Also "command: G1... "and"response:ok" are not outputted.
I think that printpi moves on next command ,when "exitEventLoop()" is called. So, something problem have occured, then "exitEventLoop()" haven't called.
About pwmWrite(), I haven't understood very much yet.
You said you not actively developing Printipi ,so please reply to me, if it's OK with you..