ATTINY 85 SLEEP MODE - microcontroller

I am new to programming microcontrollers and I've just started using Attiny85. I am trying to build a circuit for LED with tactile switch. Every time the tactile switch is pressed it jumps the LED to next state of operation. Since it is battery operated, when the LED is OFF I want the attiny 85 to consume as low current as possible. As of now it is consuming 4mA when the LED is OFF without sleep mode. So I tried the power down mode for Attiny 85 but some how i am stuck in the power down mode
if(count == 8){
analogWrite(0,LOW);
//Serial.println("I am OFF");
//Serial.println(count);
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //Power down everything
sleep_mode();
sleep_disable();
}
It is successfully entering the sleep mode but i am not able to get out of it. Can please someone help. I want the Attiny 85 to get out of the sleep mode when the tactile switch is pressed again. The switch is on pin 7 i.e. PB2 of attiny 85.

Please refer to the datasheet, section 7.1 Sleep Modes at page 34.
In the table you can see, in Power-down mode only 3 sources can wake up the CPU:
INT0, only level interrupt and pin change interrupt
USI module start condition
Watchdog interrupt
That means, if you want the part to wake up when button has been pressed, then best option will be to configure the pin change interrupt.
First you need to configure an interrupt service routine (ISR). The ISR is required just to handle the interrupt event, without it the program will be restarted. Since there is no action required, the ISR can be empty:
#include <avr/interrupt.h>
EMPTY_INTERRUPT(PCINT0_vect);
next you need to configure pin change interrupt (refer to the section 9.2 External Interrupts in the datasheet)
E.g.:
// I don't know which pin do you use for the button
// Let's assue it is PB0 which corresponds to PCINT0
// (see section 1. Pin Configurations)
PCMSK = (1 << PCINT0); // set pin change mask to PCINT0
GIMSK = (1 << PCIE); // enable pin change interrupt
sei(); // enable global interrupts
That's all. After the interrupt is configured, any logical level change at the input will cause the CPU to wake up.

Related

Problems sending SPI Data from STM32 to arduino

I'm trying to learn how to communicate via SPI with STM32 but I've run into some problems.
The first step i took was to implement SPI communications using two arduino unos: the master writes a byte and the slave responds with another byte according to the input (when the master sends anything, triggering the exchange). Everything worked as it should to the best of my knowledge.
The second step is the one I'm stuck at which is to replace the master arduino with a NUCLEO-F767ZI board. I've set up SPI1 using the auto generated code for now, and I've set it up with what I think are the default options. In the main, I send a single byte to the arduino, and this is where the problem starts:
By using the serial port in the arduino I can see that it does receive data, but usually bit shifted. So if I send a 16, i usually get a 32 or other power of two in the arduino (see attached image)
I'm using clock polarity 0 and clock phase 0 on both microcontrollers (so clock idle on low and sampling on the rising edge). Just to be sure I've tried all possibilities but to no avail, it still doesn't work properly, and I don't really know why. Another thing I considered was that perhaps the clock is running too fast (the peripheral clock is set to 16 MHz), but if I change the prescaler to anything other than SPI_BAUDRATEPRESCALER_2, i stop getting any data on the arduino, only 0s, which I find odd, I would expect it to work just the same if only the master controls the clock.
Just for completeness, here are the spi settings I'm using:
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
The arduino slave code (I've removed the reply part for now):
void setup (void)
{
pinMode(MISO, OUTPUT);
Serial.begin(115200);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
//Check arduino SPI settings, outputs 11000000, so CPHA and CPOL = 0
Serial.println("SPCR");
Serial.println(SPCR,BIN);
} // end of setup
void loop(void){
}
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;
Serial.println(c);
}
}
STM32 master code (ommiting irrelevant parts):
MX_SPI1_Init();
uint8_t data = 16;
while (1)
{
HAL_SPI_Transmit(&hspi1, &data, 1, 100);
HAL_Delay(500);
}
Does anyone have a clue as to why this could be happening? I've found nothing on the prescaler issues and all bitshifting issue posts say that the problem is with clock phase or polarity discrepancies, which I've verified is not.
Thanks in advance
SPI clock rate input to Atmega328P should be lower than Fosc/4
SPI requires the use of nCS wire. An SPI slave will reset it's logic on deassertion of nCS, but if nCS is always at a low level - any missed clock pulse would propagate to the next transfer, shifting the data.
Stm32F7 has NSSP: NSS pulse management - the option for issuing CLK pulse between data bytes. To deassert nCS pin between larger transfers SPI shoud either be disabled and then reenabled before the next transfer, or nCS management should be implemented in the software. In a later case make sure to deassert nCS only after all CLK pulses are completed.
Arduino UNO have Atmega powered from 5V, Stm32 is powered from 3V (on some boards it's 3.3V). Logic high input minimum for the Atmega328 is 0.6VCC, 5V * 0.6V = 3V, wich is on the edge. See this question
A scope would help a lot to solve such cases.

Arduino for TTL triggering: trigger received as soon as pinmode is defined

I've got an Arduino Uno with a shield from Zaber (X-AS01). I use one of the digital outputs from the shield to provide a 5V trigger signal (when 5V signal is received by the connected device, data acquisition starts).
However, as soon as my script is uploaded, the external device registers a trigger signal although I have not put the pin to HIGH. This behaviour is happening as soon as I declare the pinmode of the corresponding pin (see code below).
When I upload another script defining other pins and triggering them, my data acquisition device is nicely showing "waiting for trigger signal".
/*
Start data acquisition
*/
int acquisition = 6; // the pin data aquisition system is connected to
void setup() {
pinMode(acquisition, OUTPUT); // Declare pin as an output
}
void loop(){
//
}
Lacking any further information by best guess is that you're either triggering to some noise or to the falling edge that you will likely observe when you turn the pinmode to OUTPUT.
However, as soon as my script is uploaded, the external device
registers a trigger signal although I have not put the pin to HIGH.
Uploading the code involves a reset of the microcontroller.
The digital pins default to INPUT on reset. That means their state is floating. Rising or falling edges might occur at any time due to noise. Once you turn them into OUTPUTs their state defaults to LOW. Possibly causing a falling edge.
I would use a pulldown resistor on the trigger pin. That way your signal is low until you set the output state HIGH

Android Things I2C read from arduino 3v3

I try to communicate, read and write, from Arduino - slave - to RPi - master - with Android Things.
If i R/W, with a level converter, from RPi to Arduino 5v (16Mhz), everything works fine.
So i decide to eliminate the level converter, and use a 3v3 Arduino mini pro (8Mhz).
The write works fine, but when i try to read from the Arduino, the signal stops.
5v_16Mhz
After the Setup to 9, 0 address, and reads to 9, the signal still low and received the data. No problem.
3v3_8Mhz
After the Setup to 9, 0 address, and read to 9, the signal goes high and the data stop.
I used the same example for the Slave:
#include <Wire.h>
byte RFID[20] = {9,8,7,6,5,4,3,2,1,1,2,3,4,5,6,7,8,9,1,2};
void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
Wire.onReceive(receiveEvent); // register event
Serial.begin(115200); // start serial for output
pinMode(13, OUTPUT);
}
void loop() {
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
Serial.println("Master ask");
digitalWrite(13, HIGH);
delay(250);
Wire.write(RFID, 20);
digitalWrite(13, LOW);
}
// function should be executes whenever data is received from master
// this function is registered as an event, but it's called every time the RPi
// call the Device.
void receiveEvent(int howMany) {
while (0 < Wire.available()) {
byte RTC_syn = Wire.read(); // receive byte
Serial.println(RTC_syn);
}
}
I really don't know how drives the signal high...
Someone can help me?
If i R/W, with a level converter, from RPi to Arduino 5v (16Mhz), everything works fine.
So i decide to eliminate the level converter, and use a 3v3 Arduino mini pro (8Mhz).
The write works fine, but when i try to read from the Arduino, the signal stops.
This is because level converter you had in the 5V/3.3V version does more than shift the voltage. It also acts as a nice high-impedance buffer between the two devices that helps keep the signal driven and avoids loading effects.
Without the buffer, your bus is likely experiencing a bit of loading. You can try to combat this by adding stronger pull-up resistors. The RPi3 has 1.8k pull-up resistors on the I2C lines, which generally works but can be marginal depending on the input impedance of the slave device. The Arduino Mini has pads to install I2C pull-ups but there are none by default.
The recommended pull-up resistance for a pure 3.3V I2C bus is closer to 1k, so you likely just need to add some stronger pull-ups between SCL/SDA and +3.3V. Anything you add will be in parallel to the RPi3 resistors so factor that into your calculation. For example, adding 4.7k resistors brings the effective resistance down to about 1.3k.
If you are unable to solve it with pull-ups, you can achieve the same buffer effect without level translation by using a line driver IC (random example).
If the level converter works, you should stick with it.
Communication protocols like I2C encode data into a series of logic HIGH and logic LOW signals. What does HIGH / LOW mean? It depends on the devices. For the majority of embedded devices, logic LOW will be ground, 0V.
For Arduinos and Raspberry Pis, the source voltage is different (3.3V versus 5V). This difference can lead to several potential issues.
The 5V signal is too high for the Arduino to handle, causing the Arduino to stop working or reboot
The 3.3V signal is not strong enough to be interpreted as logic HIGH. Embedded devices have circuits that round signals to HIGH/LOW, and the thresholds may not be entirely even. A 5V input may only accept 4.5V or higher, interpreting everything else as LOW or in an indeterminate state.

STM32 communication with A4899 stepper motor driver

I want to write a stepper motor driver with a STM32L152RE.
I would like to control the position of the stepper motor with a potentiometer.
As I am new, I do not know how to communicate with (DIR, STEP).
Can someone give me a light or show me a way?
I'm using an A4988 - DMOS Microstepping Driver with Translator And Overcurrent Protection
I tried to use STM32 tim, but I could not.
Actually I have wrote whole driver for a4988, it is irq based. But I can't uncover it.
I can describe a path how to start. Anyway you should have some kind of hardware, because A4988 needs extra components for current control (resistors), and some capacitors..
You could try POLOLU HW.
If you have some kind of custom board, there may be some flaws.. So recheck pins.
Especially ROSC pin, SENSE1, SENSE2 pins as those may cause that motor wont work even if other pins are ok.
ROSC pin is for low power mode, so here you should calculate, if you just ignore it, be sure to connect at least to 10k resistor. Don't let it float. SENSE1, SENSE2 pins can be connected to 0.25omh resistors. You should check it.
Also from power pins very decisive VREG pin. It should get from 0 to 2000mV if I remember. Actually it controls current for your motor. So it depends on your stepper motor. Here also may appear nasty flaws. For example you have small stepper motor, and setting too high VREG value, than A4988 will sink too much current and your motor will glitch. Anyway you should read A4988 data sheet very accurately.
DIR PIN is simply for direction, push-pull pin configuration and HIGH/LOW values controls direction, clock wise, anti clock wise.
RESET INPUT PIN A4988 must get HIGH from your MCU.
ENABLE INPUT PIN A4988 must get LOW from your MCU.
SLEEP INPUT PIN A4988 must get HIGH from your MCU, also it is very useful to control it when your stepper job done, else if you leave it always HIGH, stepper motor will eat current and will heat up at idle state.
Also there are 3 MICROSTEPPING PINS, those are for controlling stepping.
As you just starting to play, it will be enough connect those pins to GND, you'll get full stepping regime.If you'll control those pins you can get other regimes like 1/2 stepping, 1/4,1/8,1/16...
And general pin is STEP pin, it should be driven with TIMER as PWM output with constant pulse width and alternating period.
Here is an example of STEP PIN control:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
GPIO_InitTypeDef init;
init.GPIO_Mode = GPIO_Mode_AF;
init.GPIO_OType = GPIO_OType_PP;
init.GPIO_Pin = GPIO_Pin_9;
init.GPIO_PuPd = GPIO_PuPd_UP;
init.GPIO_Speed = GPIO_Speed_Level_2;
GPIO_Init(GPIOA,&init);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_2);
for example I connect STEP output from MCU PA9 to A4988 STEP input. Which can be driven from timer as PWM. Check your concrete MCU datasheet.
Firstly output pin should be configured as AF, with push-pull and resistor is UP.
Also setup line for alternating pin.
Now configuring timer:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef timerInitStructure;
timerInitStructure.TIM_Prescaler = 48;
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = 0;
timerInitStructure.TIM_ClockDivision = 0;
timerInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &timerInitStructure);
TIM_OCInitTypeDef osc;
osc.TIM_OCMode = TIM_OCMode_PWM1;
osc.TIM_OutputState = TIM_OutputState_Enable;
osc.TIM_OutputNState = TIM_OutputNState_Disable;
osc.TIM_Pulse = 1000;
osc.TIM_OCPolarity = TIM_OCNPolarity_High;
osc.TIM_OCNPolarity = TIM_OCNPolarity_Low;
osc.TIM_OCIdleState =TIM_OCIdleState_Reset;
osc.TIM_OCNIdleState =TIM_OCNIdleState_Set;
TIM_OC2Init(TIM1, &osc);
TIM_Cmd(TIM1, ENABLE);
Here I configure 1us timer, as my MCU frequency is 48MHz.
Also you have configure that timer would drive PWM output.
TIM1->CCR = 10; with this register I can control pulse width, in this example it is 10us.
TIM1->ARR = 30; with ARR register I can control period, so it means STEP pulse frequency which is equal to stepper motor speed. In this case 30us.
If you are using HAL and CUBEMX you can get those configurations pretty fast.

Multiple Arduino Interrupts on same pin

In the following code, why does ISR2 never run?
const int in = 19;
const int LED = 9;
int flag;
void setup() {
pinMode(in, INPUT_PULLUP);
pinMode(LED, OUTPUT);
attachInterrupt(digitalPinToInterrupt(in), ISR2, RISING);
attachInterrupt(digitalPinToInterrupt(in), ISR1, FALLING);
}
void loop() {
if (flag) {delay (100); flag = false;}// debounce
}
void ISR1(){
digitalWrite(LED, LOW);
// Turn Off the motor, since, Limit Switch was engaged
flag = true;
}
void ISR2(){ // Limit Switch was disengaged.
digitalWrite(LED, HIGH);
delay(100); // Debounce, so I do not receive spurious FALLING edges from this.
}
Does the Arduino not allow you to attach two interrupts on the same pin even if the interrupts are programmed for different events?
In my setup, pin 19 gets a signal from a limit switch used in a motion control setup. When the limit switch is engaged, the in pin gets LOW signal. Thus, I first see a FALLING edge followed by RISING edges and FALLING edges due to mechanical bounce. I handle the debouncing correctly in this case.
However, imagine the Limit Switch was sitting in engaged state for a while, and then I reverse the motor causing the Limit Switch to disengage, this will send a RISING edge followed by FALLING and RISING edges. I need to ignore these edges since nothing is in danger. The ISR2 was written with purpose of capturing the first RISING edge when the Limit switch disengages, and then debouncing it so that the following FALLING edges are ignored. But now that ISR2 never gets called, how can I deal with this situation?
P.S. My microcontroller is ATMEGA 2650, It's a Arduino Mega board.
ISR2 never runs because there can be only one interrupt service routine for any interrupt source and you have replaced ISR2 with ISR1 as the sercice routine for this interrupt. If you reordered your code and attached ISR1 before ISR2 then you might see ISR2 run but not ISR1.
A typical microcontroller has an interrupt vector table that associates an interrupt service routine with each interrupt source. There can be only one service routine for each interrupt source. If you assign an new service routine then you're replacing the old service routine. There are not separate service routines for the rising and falling edges. Rising versus falling edge is a configuration setting for the interrupt source to determine when that interrupt should fire. The interrupt source cannot be configured to fire on both edges simultaneously.
However you may be able to reconfigure the interrupt for the other edge after you have received the interrupt for the first edge and debounced the transition. This way your code will ping-pong back and forth configuring for one ISR and then the other.
Why are you saying that it never gets called? I think that it is called, but you don't notice it because the led does not change its state (because there are bounces).
Anyway, you are NOT debouncing it correctly. Let's do an example: you hit the endstop. ISR1 gets called, so flag is true. Ok, at next loop the motor will be stopped. But... Now the switch bounces. ISR2 gets called, and the delay function in it waits for 100ms before exiting the ISR. Result: you delayed the motor stop function by 100ms.
I suggest you to read my answer here, particularly the second case. And I suggest you to use my code instead of yours, since this way you will be able to IMMEDIATELY stop the motor, without bounces nor any other kind of problems.

Resources