Looking for some help please. This maybe a bit long, but bear with me…
I have an Adafruit BME280 (i2c & SPI Temp sensor) that I thought would be rather cool to plug into the PW and see if I could get any data out of it and onto the screen… Success.
Then I thought Id plug in my spare Nokia 5110 and see if I could get the data form the BME280 onto the Nokia LCD… Success:slight_smile:
Riding hi on my successes I thought it would be cool to add a push-button on/off switch and a power LED also.
Right from the off I read that the wake function requires pin 5 & 6 to be shorted momenterily and pin 5 is also the pin used by i2c1.
My immediate thought was to not worry about it!
I followed the tutorial here to connect the button:
Everything works just as it should but it also killed the i2c1 line because now the BME280 python library doesn’t work and when I do i2cdetect -y 1 in Terminal it no longer shows any device(s).
My next thought was to move the BME280 from i2c1 to i2c0. I put dtparam=i2c_vc=on in /boot/config.txt and rebooted my pi.
Now when i do i2cdetect -y 0 I get the same information as when I did i2cdetect -y 1 but there is no (magic) 77 identified in the i2c0 channel (to represent that the BME280 is connected).
I have connected the SDI pin on the BME280 to pin 27 and the SCLK pin on the BME280 to pin 28 on the PIZero.
Any ideas as to why the BME280 is not being registered on i2c0 ???
I also thought about running the BME280 on SPI, but that kinda defeated the object of learning a bit about I2c and also after a quick google, I couldn’t find any SPI drivers for the BME unit!
Any help or insight would be much appreciated.
That sounds like a unique situation haha. I’ve never added a hardware power button myself, so to avoid shorting something out, I’ll work on the second part of your question. I can’t imagine why it wouldn’t be registering on I2C0, that’s a little strange, but as far as SPI goes, if you’ve already got some I2C devices working, learning a bit about SPI could be good as well.
If there are no readily available drivers, then you might have to do things the old fashioned way haha. Look up the data sheet and experiment with the right SPI bytes to send.
I’m surprised you’ve had a problem with connecting I2C1_CLK to ground - this should be a safe operation if the pin is indeed set up as an I2C bus. Are you sure you didn’t perform the shorting operation while it was configured as a regular GPIO output?
Do you have any way to measure the I2C1 connections (oscilloscope or logic analyser)? My thinking here is hopefully it’s just the sensor, not the Pi. Do you have a spare (cheap) I2C device that you can attempt to connect to the bus, like an EEPROM or other sensor? Without the power switch of course.
Before you press on trying to use I2C0, read this Sparkfun article which describes the only acceptable use-cases for I2C0. In a nutshell, you can’t freely use it for your own devices - it’s only good for reading from an EEPROM at boot.
Either way, it doesn’t seem like the article you’ve linked was written with I2C bus use in mind, sadly
I may have inadvertantly confused everyone.
To be clear, when I don’t use the I2C channel the button works perfectly. When I don’t use the button (more accurately when I stop listening for the falling edge on pin 5 as per the button link I provided), the i2C channel (pins 3&5) and BME280 work perfectly together.
I think the problem comes when the link I provided to the button utilises the listening for the falling edge on pin 5. This appears to kill the i2C1 functionality.
Quite separately to the above, the i2c0 doesn’t seem to allow the BME280 to work on that channel when I enable it (via dtparam=i2c_vc=on in /boot/config.txt), although to the best of my knowledge i2c0 is now enabled. I need to study the link you provided more, but it would appear i2c0 won’t work for me.
As for getting SPI to work… I have it working for my Nokia 5110 LCD, but I suspect getting the BME280 to work on SPI may currently be WAY above my skill level!
My current thinking is that my immediate solution maybe to have 2 power buttons. Shorting pins 5 & 6 together will only wake the pi without software intervention, it will not shutdown. So, if the unit is turned off, there is no issue shorting the pins because there will be no risk of damaging the unit or BME280. I can then modify the shutdown code to listen on a pin that is not otherwise allocated to i2C, SPI or 1-wire etc. The only downside is a need for 1x ON button and 1x OFF button. The other option is to understand exactly where in the operating system it sets pin 5 as the shutdown pin and allocate it elsewhere.
Ah ok, I’m with you now, @Jon13024.
If you find a solution to redefining the wake-functionality then it’ll be really useful for others who want to use that function and I2C in their projects. As it stands, having both functions on the same pins won’t work, although there should be no danger of pulling an I2C connection to ground - this is how the hardware layer works, so at worst all you’ll do is corrupt a transaction that’s taking place.
Alternatively, there may be a hardware solution available to you:
Use a transistors to re-route the button signal so that when the Pi is off (halted), the signal goes to hardware-wake and when the Pi is on, the signal is re-routed to a separate GPIO pin used for Off-triggering. This way, you’ll approximately have the 2-button alternative that you mentioned on the Pi side of things, but you’ll have only one button…
Here’s a quick-and-dirty sketch of what I was thinking. I haven’t researched whether this will work, so it’s purely just to illustrate the thought-train. The idea is that a 1-button solution may only require a single transistor and resistor to disconnect the button from the I2C bus once the Pi has woken up, by driving CTRL low.
SHUTDOWN listens for an edge to trigger a shutdown.
When halted, if CTRL is high-impedance then the transistor will be on, connecting the switch to WAKE
To clarify, that’s an N-channel, logic-level mosfet that I’ve used.
Apologies for the kindergarten-scrawl. I never got my pen-license.
Wow:slight_smile: Thanks Michael. This is great and I think has great potential.
I’ll definitely have a play and see if I can make it work. I can sort of follow the idea, but my knowledge of specifying transistors is simply not good enough. I did a google on n-channel logic level moffset and came up with this:
Would you be able to confirm an appropriate Mofset that I could buy and give the above a try?
Also, I googled sizing resistors and came to the Sparkfun page - easy for me to understand!
Just need an appropriate mofset and then I feel part two of the the project coming on!
Good resource, @Jon13024!
My go-to logic level MOSFETs are:
Small currents (<200mA) - 2n7000.
Large currents (200mA - 20A) - IRF540N
So for this circuit I would just reach for a 2n7000 because I know and love them.
Finally had some time to continue this problem. Further to Michael’s 2n7000 idea, this is the wiring diagram I came up with, including the i2c device and a power led that works off the Serial TX pin.
When I do an i2cdetect -y 1 from a terminal window I can see the BMP280. When the Pi is shutdown, the button will wake the Pi.
The shutdown code:
import RPi.GPIO as GPIO
subprocess.call(['shutdown', '-h', 'now'], shell=False)
Before I run the above code, the I2C protocol works. Once I run the code and then run i2cdetect -y 1 or try to get data from the BMP280, the machine shutdown!
This leads me to believe that either Ive wired the 2n7000 incorrectly, or my code is wrong… or both!!
Looking at Michael’s diagram again this morning, Im beginning to wonder if the 10k resister on the gate line is fed from the 3.3v pin and connect between the gate and GPIO pin and not in-line (and without 3.3v) as Ive shown it?
Im a bit out of my depth here, so any help would be greately appreciated!
Good to see you’ve thoroughly rolled your sleeves up for this problem, Jon! This is exactly the kind of content we want to see on the forums .
Correct - The resistor in my circuit diagram is “pulling up” the gate of the 2n7000. This means the transistor is always on unless the GPIO line (BCM5 in your sketch) is pulled low.
To reiterate: The transistor in my schematic will always be conducting unless the GPIO is pulled low. So if the GPIO is for instance high impedance (reset state) or logic-high, the transistor will still conduct anyway.
I’ll get back with an updated schematic for your particular application to hopefully clear things up.
Here’s the update.
Here’s an idea of sequencing:
- Push button to wake Pi.
- Script inhibits the wake button by pulling mosfet gate low
- shutdown interrupt is enabled
- push button to shut down Pi, this should also reset the CTRL GPIO to re-enable the wake functionality.
- Pi shuts down
Again, there may be funny little quirks to this circuit that I have not fully realised and it’s successful operation relied on both the circuit AND the code working.
Thanks Michael… This is all beginning to make my brain hurt
Im pretty sure Ive got the circuit wired correctly but its just not performing as I’d expect.
This is my listen-for-shutdown.py code:
import RPi.GPIO as GPIO
#subprocess.call(['shutdown', '-h', 'now'], shell=False)
print ("Should be shutting down now")
I believe this should invoke your idea of sequencing, i.e. make BCM 5 HIGH and thus allow power to flow from source to drain. I think that means though that my code to talk to the BME280 will need to set pin 5 LOW before poking the sensor and then return it to HIGH afterwards.
Problem is that despite setting BCM5 LOW and then poking the sensor, it still triggers a falling edge on pin 17 and thus the shutdown script shutsdown.
Here is my code for the sensor:
from Adafruit_BME280 import *
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import RPi.GPIO as GPIO
# Initialise the BME280 Sensor
sensor = BME280(t_mode=BME280_OSAMPLE_8, p_mode=BME280_OSAMPLE_8, h_mode=BME280_OSAMPLE_8)
degrees = sensor.read_temperature()
pascals = sensor.read_pressure()
hectopascals = pascals / 100
#humidity = sensor.read_humidity()
print ("Temp (^C): %0.2f" % degrees)
print ("Pressure (hPa): %0.2f" % hectopascals)
Anything obvious that I am doing wrong? Im not sure if BCM 5 should be an IN or an OUT.
So far I have figured out that the listen-for-shutdown.py code ‘shutsdown’ when the BME280 sensor is initialised, i.e. after GPIO 5 has been set to LOW and before the sensor reads the ‘degrees’.
Im convinced the MOFSET isn’t switching correctly, perhaps more accurately, Im convinced its not switching completely off.
To test the theory Ive written this bit of code:
import PRI.GPIO as GPIO
As for the circuit:
5v from Pi to Drain
Source to LED to 330ohm resister to GND
GND to GND on Pi
BCM 5 to Gate through 10k resister
This simply switches the LED ON/OFF after 5s but the doesn’t go fully out on LOW.
Ive found out that by me holding a resister to the gate is more effective / just as effective at turning the MOFSET on than the Pi. I presume this is something to do with static electricity?
Thoughts and advice please?
What you’re seeing is the transistor operating in the triode region: You are correct, it is not fully on or fully off.
I haven’t analysed why the original circuit might not work, but I can tell you your test circuit needs adjusting to the following. N-channel mosfets are better at sinking current - The circuit you had would be the test-case for a P-channel mosfet.
Give this a go and you should see the LED behave as expected.
FYI: This is the standard method of driving a non-inductive load with an N-ch mosfet. It’s a good little circuit block to keep up your sleeve. Substitute the 2n7000 for any other logic-level mosfet and you can drive high-power or higher voltage loads with this.
I eventually got the 2n7000 switching… My problem seemed to be that I was feeding the 3.3v through PIN 1, i.e. fixed 3.3V - It was only when I realised that I needed to drive a GPIO pin HIGH to give 3.3V (and thus also had the ability to drive it LOW) that things started to work as expected:slight_smile:
When I fed the Drain with 3.3V from Pin 1 and set GPIO5 HIGH or LOW, the LED (on the source side) flashed but never turned off, only got dimmer when GPIO5 went LOW. I found that when I fed the Drain from BCM6 (instead of PIN 1) and set this pin HIGH or LOW, the LED (again on the source side) turned ON and OFF - But that then leaves me wondering whats the point of my GPIO5 (CTRL) Line?
So, with BCM5 as my CTRL and BCM6 as my 0V and 3.3V line, the 2n7000 appears to switch ON and OFF as expected.
My current problem:
When I drive BCM6 LOW to switch off the 2n7000 and get ready for using the i2C bus, BCM 17 goes LOW and the falling edge interrupt is triggered in my listen-for-shutdown.py code.
I think the solution is to add GPIO.remove_event_Detect(17) in my code just before I drive BCM6 LOW - the problem however is that I get the error below:
RuntimeError: no access to /dev/mem. Try running as root!
Googling this error seems to suggest its a permissions thing, but Ive spent a lot of today trying to figure it out… to no avail.
Any thoughts or words of wisdom???