Direct GPIO Control

904 views
Skip to first unread message

Bob S

unread,
Apr 14, 2017, 9:28:25 PM4/14/17
to SonoffUsers
I am creating an application to open and close the blinds.  The mechanical operation of the blinds requires a rotary motion for which I am using a stepper motor controlled by an EasyDriver controller.  The interface to the motor controller requires 5 GPIO pins, for enable, direction, step, etc.

The MQTT control will look like cmnd/device/BLINDS OPEN or cmnd/device/BLINDS CLOSE

In order to accomplish all this I need to write some custom code that uses the GPIO pins in a "traditional" way, e.g. digitalWrite(pin,HIGH);

It's not clear to me how to get direct control of the pins here.  Can someone tell me how best to accomplish this within the existing  framework?

I am using a WeMos D1 mini.

Thanks,
Bob

David Lang

unread,
Apr 14, 2017, 9:34:08 PM4/14/17
to Bob S, SonoffUsers
using the tasmota firmware, there is no easy way to do what you're looking to
do.

see https://github.com/arendst/Sonoff-Tasmota/issues/288 for my thoughts on what
is needed.

But it would take quite a bit of change, both in the mqtt routines, and in
routines to track the position tracking and signal timing.

David Lang

On
Fri, 14 Apr 2017, Bob S wrote:

> Date: Fri, 14 Apr 2017 18:28:24 -0700 (PDT)
> From: Bob S <b...@sculley.net>
> To: SonoffUsers <sonof...@googlegroups.com>
> Subject: Direct GPIO Control

Julian Knight

unread,
Apr 18, 2017, 4:44:13 PM4/18/17
to SonoffUsers
Much easier to do with your own firmware rather than Tasmota. I use the D1-mini's all over and they are very easy to work with using the Arduino IDE with the ESP boards addon. Reference WiFi and MQTT libraries and you are away.

Will W

unread,
Apr 19, 2017, 2:20:52 AM4/19/17
to SonoffUsers
I am brand new to Sonoff but I have been a Pi-Arduino geek for a long time.  So this may not fit your need but running a stepper form an Arduino Uno board is very easy.  You could use your Sonoff to tell your Arduino to open or close the blinds with just 1 GPIO pin.  Then your Arduino has plenty of GPIO to run the stepper.

Julian Knight

unread,
Apr 19, 2017, 4:18:02 PM4/19/17
to SonoffUsers
An ESP8266 device such as a Wemos D1-mini is every bit as easy to program as an Arduino (that's how I got started) and can generally use the same Arduino libraries too. The main difference being that you have direct Wi-Fi available. With the MQTT and Wi-Fi libraries, reading/writing MQTT topics is so easy. And the GPIO stuff is pretty much identical to Arduino.

Will W

unread,
Apr 19, 2017, 5:35:20 PM4/19/17
to SonoffUsers
Cool, need to start tinkering with one of those!

Julian Knight

unread,
Apr 20, 2017, 12:11:29 PM4/20/17
to SonoffUsers
Order a bunch and order them early as they come from China - unless you happen to be in Asia, that means a bit of a wait. But well worth the wait as they are so cheap and easy to work with. There are plenty of alternatives too of course but I like the packaging of the D1-mini as it takes away all the hassle of power management which I've always struggled with on the ESP8266 - not being an electronics expert.

Bob S

unread,
Apr 21, 2017, 11:40:06 AM4/21/17
to SonoffUsers
Thanks for your feedback.  I decided to pursue my idea because I didn't want to lose all the infrastructure (WiFi, MQTT, etc) that is baked into this app, and actually, I think I found a pretty easy way to do what I wanted.  I defined a new device type (WEMOS_STEPPER) and 5 new pin designations:

 
 // support for stepper motor
  GPIO_MSTP
, //#define stp 2 - move
  GPIO_MDIR
, //#define dir 3 - direction
  GPIO_MMS1
, //#define MS1 4 - step size
  GPIO_MMS2
, // #define MS2 5 - step size
  GPIO_MEN
, // #define EN  6 - enable
...
   
{ "WeMos Stepper", // WeMos stepper motor definition
     GPIO_USER
,        // GPIO00 D3
     GPIO_USER
,        // GPIO01 TX Serial RXD
     GPIO_USER
,        // GPIO02 D4 Wemos DHT Shield *
     GPIO_USER
,        // GPIO03 RX Serial TXD and Optional sensor
     GPIO_MDIR
,        // GPIO04 D2 Motor Direction *
     GPIO_MSTP
,        // GPIO05 D1 step size 1 *
     
0, 0, 0, 0, 0, 0, // Flash connection
     GPIO_MMS1
,        // GPIO12 D6 stepsize 1
     GPIO_MMS2
,        // GPIO13 D7 stepsize 1
     GPIO_USER
,        // GPIO14 D5 *
     GPIO_USER
,        // GPIO15 D8
     GPIO_MEN
,         // GPIO16 D0 Wemos Wake Motor Enable *
     GPIO_ADC0        
// ADC0   A0 Analog input
 
}

 
Then I added a block to the MQTT command parser to look for the "blind" command:
    if (!strcmp(type,"BLIND")) {
     
if ((data_len == 0) || (payload > 4)) payload = 9;
      do_cmnd_blind
(index, payload);
     
return;
   
}


Finally, the actual code.  This is a test only just to move the motor:
void do_cmnd_blind(byte device, byte state)
{

pinMode
(pin[GPIO_MSTP],OUTPUT);
pinMode
(pin[GPIO_MDIR],OUTPUT);
pinMode
(pin[GPIO_MMS1],OUTPUT);
pinMode
(pin[GPIO_MMS2],OUTPUT);
pinMode
(pin[GPIO_MEN],OUTPUT);
  resetEDPins
();
  digitalWrite
(pin[GPIO_MEN], HIGH); // enable the driver
 
if (state)
    digitalWrite
(pin[GPIO_MDIR], LOW); //Pull direction pin low to move "forward"
 
else
    digitalWrite
(pin[GPIO_MDIR], HIGH); //Pull direction pin high to move "backward"
   
 
int x;  
 
for(x= 1; x < 1000; x++)  //Loop stepping enough times for motion to be visible
 
{
    digitalWrite
(pin[GPIO_MSTP],HIGH); //Trigger one step forward
    delay
(1);
    digitalWrite
(pin[GPIO_MSTP],LOW); //Pull step pin low so it can be triggered again
    delay
(1);
 
}
resetEDPins
();
}
//Reset Easy Driver pins to default states
void resetEDPins()
{
  digitalWrite
(pin[GPIO_MSTP], LOW);
  digitalWrite
(pin[GPIO_MDIR], LOW);
  digitalWrite
(pin[GPIO_MMS1], LOW);
  digitalWrite
(pin[GPIO_MMS2], LOW);
  digitalWrite
(pin[GPIO_MEN], LOW);
}
This works ok, except it seems to create some kind of instability in the system.  After a couple of "BLIND" commands the MQTT connection fails, and I get a variety of exceptions:

Exception (28):
epc1
=0x4000bf0e epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
ctx
: cont
sp
: 3fff23a0 end: 3fff2680 offset: 01a0
>>>stack>>>
3fff2540:  3fff455c 3fff3cb0 3fff2570 3ffe96dc  
3fff2550:  3fff455c 3fff3cb0 3fff257c 40220b3a  
3fff2560:  3fff455c 3fff3cb0 3fff3c8c 4021d2f8  
3fff2570:  00000000 00000000 00000000 3fff7f34  
3fff2580:  0000001f 0000000d 3fff3034 0000000f  
3fff2590:  0000000a 3fffdad0 3fff1658 00000030  
3fff25a0:  3fff301c 0000000f 00000000 3fff7fec  
3fff25b0:  0000000f 00000004 3fff7fd4 0000000f  
3fff25c0:  00000003 3fff3aa4 0000000f 00000003  
3fff25d0:  3fffbf4c 0000008f 0000008c 4021908c  
3fff25e0:  3fff3ccc 00000000 3fff1660 00000000  
3fff25f0:  00000000 4021b110 0000000a 3fff1660  
3fff2600:  00000000 00000000 3fff3c8c 3fff1658  
3fff2610:  00000139 3fff3cb0 3fff3c8c 4021c0b3  
3fff2620:  3ffe98f0 00000000 3fff1660 00000000  
3fff2630:  3fffdad0 3fff1658 40221640 3fff1660  
3fff2640:  3fffdad0 00000000 3fff1650 402049d6  
3fff2650:  00000000 00000000 00000001 40217106  
3fff2660:  3fffdad0 00000000 3fff1650 4022168c  
3fff2670:  feefeffe feefeffe 3fff1660 40100718  
<<<stack<<<
 ets
Jan  8 2013,rst cause:2, boot mode:(3,6)
load
0x4010f000, len 1384, room 16
tail
8
chksum
0x2d
csum
0x2d
v09826c6d
~ld
ø



Is there some problem with a long running command processor?  Is there an interrupt or something that should be disabled while the stepper code is running?

Thanks,
Bob

David Lang

unread,
Apr 21, 2017, 12:03:44 PM4/21/17
to Bob S, SonoffUsers
I would guess that you are tripping a watchdog of some sort.

David Lang

On Fri, 21 Apr 2017, Bob S wrote:

> Date: Fri, 21 Apr 2017 08:40:06 -0700 (PDT)
> From: Bob S <b...@sculley.net>
> To: SonoffUsers <sonof...@googlegroups.com>
> Subject: Re: Direct GPIO Control

Bob S

unread,
May 4, 2017, 4:25:17 PM5/4/17
to SonoffUsers
I have actually been successful in creating what I needed.  The problem is perhaps simpler than I presented it originally because I am using a stepper motor driver external from the D1 Mini, so I don't have to control the motor directly.  In and case, I'll be happy to share the code with anyone who is interested.

I ended up using timer 0 to run the stepping loop to avoid any conflicts with other timers, interrupts, etc.  This is working great, but timer 0 uses the cpu cycle count to determine when to fire, so the timing is controlled by the cpu frequency.  I would like to find a way to programmatically determine the processor speed (80 vs. 160MHz).  I have found some fragments that indicate that this is possible, but it is apparently not implemented here.  Does anybody know what would be required?

Thanks.

Black Talon

unread,
Jan 7, 2019, 4:48:47 PM1/7/19
to SonoffUsers
Oh yeah, I would be very interested in how you did it.  This sounds awesome.
Reply all
Reply to author
Forward
0 new messages