ATtiny13 project problems - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 09:40:17 am
content: I've written the following program, it takes an analogue reading off a temperature sensor and produces PWM accordingly. I'm getting nothing from it even if I comment out most of the code and just leave the PWM duty setting (last two lines).I've used a lot of functions that I've included below and they are just to tray and keep the code rational and one day I'll reuse the functions in other programs once they workCode:#define F_CPU 4800000UL#include <avr/io.h>#include "attiny13.h"uint16_t T; //Temperature readinguint8_t D; //Duty out settinguint16_t Ton = 323; //cut in/out temperatureuint16_t Tset = 124;//Temperature at which ramp startsuint16_t wait_time = 5000;int main(void){bit_s (DDRB, PB0); //pin 0 is digital output for PWMvreff_vcc();ch0();adc_clk_div8();adc_on();fast_pwm_a();while(1){T = adc_result();if (T>Ton);D = 255;if ((T > Tset) && (T < Ton)) // speed for when temperature is between min and set temperatureD = 204;if (T < Tset) //if over t set map speed to temperatureD = map(T, 66, 124, 25, 127);if (T < 66) //if temp reads under -30 assume probe disconnected and run full speedD = 13;pwm_a_duty(D);delay_ms(wait_time);}}Sections from the attiny13.h used are as follows:Code:#define bit_get(p,m) ((p) & (m))#define bit_s(p,m) ((p) |= (m))#define bit_c(p,m) ((p) &= ~(m))#define bit_flip(p,m) ((p) ^= (m)) // p is the register, m is the bit name#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))#define BIT(x) (0x01 << (x))Code:void delay_ms(int ms) // millisecond delay function to use when the time is a variable and not a constant{while (ms--)_delay_us(1000);}Code:long map(long x, long in_min, long in_max, long out_min, long out_max){return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;}Code:void dO (int port, int pin) // make the pin a digital output, port and pin being the port name and pin name{bit_s (port, pin);}void dI (int port, int pin) // make the pin a digital input, port and pin being the port name and pin name{bit_c (port, pin);}Code:void vreff_vcc (void){bit_c (ADMUX, REFS0);}void ch0 (void){bit_c (ADMUX, MUX1);bit_c (ADMUX, MUX0);bit_s (DIDR0, ADC0D);}void adc_clk_div8 (void){bit_c (ADCSRA, ADPS2);bit_s (ADCSRA, ADPS1);bit_s (ADCSRA, ADPS0);}void adc_on (void){bit_s (ADCSRA, ADEN);}Code:void fast_pwm_a (void) //fast non inverted pwm with no prescaler{dO (DDRB, PB0);bit_s (TCCR0A, COM0A1); //set pin as clear on match set on topbit_c (TCCR0A, COM0A0);bit_c (TCCR0A, WGM02); //fast pwm mode setbit_s (TCCR0A, WGM01);bit_s (TCCR0A, WGM00);bit_c (TCCR0A, CS02); // no prescalerbit_c (TCCR0A, CS01);bit_s (TCCR0A, CS00);}void pwm_a_duty (uint8_t duty_a){OCR0A = duty_a ;}

author: Psi
author_rank: Super Contributor
timestamp: May 18, 2014, 09:53:19 am
content: That "if" statement does nothing because it's terminated by a semicolon before any statement.So D = 255; becomes a separate statement which will always execute.So pwm is always 255 (100% high)Quote from: Simon on May 18, 2014, 09:40:17 am

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 09:54:43 am
content: ah, brilliant, thank you, although the output is actually always 0 but that surely needs correcting, I'll see what happens

author: Psi
author_rank: Super Contributor
timestamp: May 18, 2014, 09:56:59 am
content: Change pwm_a_duty(D); to "pwm_a_duty(128); and see if you get a square wave on the output.That will atleast check if the pwm part of it is working.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 10:04:02 am
content: Hm, still nothing

author: Psi
author_rank: Super Contributor
timestamp: May 18, 2014, 10:11:46 am
content: PB0 shares the function of MOSI,Is the PB0 pin being pulled High/Low by your programmer at all? It should either be connected with a resistor or your programmer should be set to go highZ during non-programming (run) state.If your programmer is always source/sinking the MOSI signal it will prevent the MCU from switching that output by shorting it. ie output connected to output

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 10:12:49 am
content: Yes i thought of that and have been removing the programmer when running the circuit.

author: Psi
author_rank: Super Contributor
timestamp: May 18, 2014, 10:24:11 am
content: I think your problem is in the use of those macrosHave a look at what this "bit set" macro is doing#define bit_s(p,m) ((p) |= (m))And then have a look at how its being used.bit_s (DIDR0, ADC0D);If we expand the macro we getDIDR0 |= ADC0D;The problem here is that ADC0D is defined as the bit position, not the value.eg, ADC0D is defined as 5 ( bit 5 of DIDR0 )so you are goingDIDR0 |= 5;when you really wantDIDR0 |= 32; // 0010 0000You need to change the macro or how you are calling it.My syntax knowledge of C macros is limited but you could..Call it like this..bit_s (DIDR0, (1<<ADC0D) );OR, instead, change the macro too..#define bit_s(p,m) ((p) |= (1<<(m)))Note: other macros have the same usage problem, not just that one.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 10:42:08 am
content: I think you are right, I should be using the BIT(x) macro as well and using it in conjunction with those macros.

author: Psi
author_rank: Super Contributor
timestamp: May 18, 2014, 10:43:37 am
content: Yes, that would be another option.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 10:45:19 am
content: it's my stupid dyslexic brain, that is why i wrote the functions in the first place to save me making errors over and over again but this is the first time i use these on this chip so have only just written my header file.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 02:08:52 pm
content: Still no joy, I'll re trawl through the datasheet to see if I've gotten the functions right in the first place and try breadboarding it.

author: nctnico
author_rank: Super Contributor
timestamp: May 18, 2014, 02:20:08 pm
content: What voltage does the chip run on? Atmel chips in general (yes that is all of them: controllers, memory, etc) don't run reliably on the lowest voltage mentioned in the datasheet.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 02:26:47 pm
content: 5 Volts

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 03:12:55 pm
content: ok sorted, I had used the wrong register name to setup the PWM mode, where I should have named register B I used A for everything so some register settings were just not happening.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 03:45:46 pm
content: although I'm yet to see the ADC bit of it work.

author: Neverther
author_rank: Regular Contributor
timestamp: May 18, 2014, 04:49:31 pm
content: I assume you want the ADC freerunning?I dont see ADSC anywhere (ADC start conversion) or ADATE (ADC auto trigger).Sample code of t13a running some fans to full on startup, then back off to pot setup ratio (usually so low they wouldnt start if it was fixed PWM).0.83$ per chip so dont go all 555 preaching.Code:#ifndef F_CPU#define F_CPU 9600000UL // CLOCKDIV8 OFF#endif#include <avr/io.h>#include <util/delay.h>int main(void){// PB4 is analog in + left adjustADMUX=(1<<MUX1) | (1<<ADLAR);// ADC on and /64 -> 150kHzADCSRA=(1<<ADEN) | (1<<ADPS1) | (1<<ADPS2) | (1<<ADATE) | (1<<ADSC);// Disable bufferDIDR0=(1<<ADC2D);// PB0 is PWMDDRB=(1<<DDB0);// Clear on compare match set on TOP and setup Fast PWMTCCR0A=(1<<COM0A1) | (1<<WGM01) | (1<<WGM00);// Setup PWM freq /64TCCR0B=(1<<CS00);OCR0A = 0xFF;_delay_ms(2000);OCR0A = ADCH;while(1) {_delay_ms(200);OCR0A = ADCH;}}

author: bingo600
author_rank: Super Contributor
timestamp: May 18, 2014, 05:01:17 pm
content: Quote from: Simon on May 18, 2014, 03:45:46 pmSimon you'd need something like this (this is for a M32 though)Code:#defineADC_ENABLE(1<<ADEN)#defineADC_CONVERT(1<<ADSC)#define ADC_VREF_TYPE((0<<REFS1) | (1<<REFS0))#defineADC_PRESCALE_128((1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)) //150 us Conversion time @11.xxx Mhzvoid initadc(void){ADCSRA = 0;ADMUX = ADC_VREF_TYPE;//AVCC voltage reference with external capacitor at AREF pinADCSRA = ADC_ENABLE | ADC_PRESCALE_128 ;// ADC Enable and Set Prescale valueSFIOR &= 0x0F;// Make sure reserved bit 0x04 is set to zero}uint16_t read_adc(uint8_t adc_input){ADMUX = adc_input|ADC_VREF_TYPE;// Internal 2.56 VREF , use the specified input pinADCSRA |= ADC_CONVERT;// ADC Start conversion (this bit is restored to zero when finished)while (ADCSRA & ADC_CONVERT); // Check the complete flag and wait until donereturn ADCW;}The while (ADCSRA & ADC_CONVERT); is importantTaken from an old demo i madehttp://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=391Edit: Also have a look herehttp://www.adnbr.co.uk/articles/adc-and-pwm-basics/Bingo

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 05:09:18 pm
content: Quote from: Neverther on May 18, 2014, 04:49:31 pmCode:int16_t adc_result (void) //return the current ADC value, the function will wait until the a conversion has ended.{uint16_t result;while( ADCSRA & (1<<ADSC)); // Wait until ADC conversion is complete..result = ADCW;return result;}What I meant was i had not tested to see if the ADC code was working. The function above should run the adc and get a result much like the arduino adc read function.I'm getting a waveform but I'm not quite sure if it's all tickety boo yet, this was originally written for the arduino on a Tiny25/85 but i made a mistake and put a tiny13 on the PCB which i was thinking of using anyhow so decided to rewrite in AVC for the 13 rather than 25/85

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 05:18:27 pm
content: Quote from: Neverther on May 18, 2014, 04:49:31 pmHaha, well what I am doing could be almost done with a potentiometer, the fans circuitry is actually low pass filtering the PWM input to a DC voltage so a thermistor and resistor in series with the output off the middle can do it crudely but I'm not going to tell my boss and potential customer that and it is already understood that I can change the parameters for them on demand and do anything else fancy that is allowable within the hardware.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 05:51:20 pm
content: ok so I'm getting a waveform and it is being generated by the program in some way but not as expected. My only assumption can be that the value is not being read properly from the ADCW register someone convinced me to use.........

author: bingo600
author_rank: Super Contributor
timestamp: May 18, 2014, 06:01:23 pm
content: Simon thishttp://www.adnbr.co.uk/articles/adc-and-pwm-basicsSuggests the register name is ADC on a T13 , not ADCWI think that page is nice for a T13.Are you running 9.6Mhz ? or the factory default ?/Bingo/Bingo

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 06:03:30 pm
content: ok I'll try ADC, I'm running 4.8MHz with no scaling

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 06:10:52 pm
content: It makes no difference with ADC, the tutorial you link to just uses ADCL in 8 bit mode, I am not doing this because i am not passing the ADC result straight to the ADC but working with it to come up with a PWM value so i need that resolution.

author: Neverther
author_rank: Regular Contributor
timestamp: May 18, 2014, 06:20:46 pm
content: Code:while( ADCSRA & (1<<ADSC)); // Wait until ADC conversion is complete.Please look at the datasheet, page 94.You need to write into the register, then check if it is still set (single conversion mode).Now you just check the register, but don't write into it to start the actual conversion.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 06:24:58 pm
content: Ah, I need :Code:void adc_go (void){bit_s(ADCSRA, BIT(ADSC));}

author: bingo600
author_rank: Super Contributor
timestamp: May 18, 2014, 06:27:55 pm
content: Quote from: Simon on May 18, 2014, 06:10:52 pmIt spooks me a bit that using ADCW didn't return a compiler error (undefined).Well now it don't (from iotn13.h)Code:/* ADC Data Register */#ifndef __ASSEMBLER__#define ADC _SFR_IO16 (0x04)#endif#define ADCW _SFR_IO16 (0x04)#define ADCL _SFR_IO8(0x04)#define ADCH _SFR_IO8(0x05)So ADC & ADCW has same def./Bingo

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 06:36:54 pm
content: Still no joy

author: bingo600
author_rank: Super Contributor
timestamp: May 18, 2014, 06:42:55 pm
content: What adc channel are you using , and what voltage reference (vcc or 1.1v ) ?/Bingo

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 06:45:54 pm
content: I'm using VCC on channel 0 - oh bugger, bet the AVRISP2 is interfering although probably not as there is a 2V input so something to convert either way

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 06:47:36 pm
content: IDIOT! I should be on ADC2 there is probably a change from the tiny25 to the tiny13

author: bingo600
author_rank: Super Contributor
timestamp: May 18, 2014, 06:53:45 pm
content: I siggest you start the conversion & read the result in the same routineCode:uint16_t read_adc(void){//ADCSRA |= ADC_CONVERT;// ADC Start conversion (this bit is restored to zero when finished)bit_s(ADCSRA, BIT(ADSC)); // // ADC Start conversion (this bit is restored to zero when finished)//while (ADCSRA & ADC_CONVERT); // Check the complete flag and wait until donewhile (ADCSRA & BIT(ADSC)); // Check the complete flag and wait until donereturn ADCW;}/Bingo

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 07:16:19 pm
content: yes i have now done:Code:uint16_t adc_result (void) //return the current ADC value, the function will wait until the a conversion has ended.{uint16_t result;bit_s(ADCSRA, BIT(ADSC));//start a conversionwhile( ADCSRA & (1<<ADSC)); // Wait until ADC conversion is complete..result = ADC;return result;}I think i meant to do it and then forgot.