Go Down

Topic: attiny85 quadratic divider 20MHz+4ports  (Read 584 times) previous topic - next topic

rokag3

Jan 22, 2018, 03:24 pm Last Edit: Jan 22, 2018, 04:09 pm by rokag3 Reason: make this post more readable
Hello,

I need to divide a quadratic encoder by 2
I have written this program that work fine on attiny 44 (no need to check)
It need to work at 20Mhz so I put a crystal on port 3 and 4 (this program must run reliably close to 20khz and it do it at 20MHz )
So far  so good
I have 2 ports in input for the incoming signal AB
I need 2 ports for output I use Portb 3 and  Portb 5(yes the reset) this is why the index in the table  slowEncoder is so heavy

Code: [Select]
//vb1.0
//rokag3 1/19/2018
//diviseur par 2 d'encodeur en quadrature
//attiny 85 20mhz using reset port as output
//
// ********************************************************************************************
//Arduino IDE & Pin Mapping
// add  2 capacitor 22picof ground to PB0 and PB1 where is the crystal 20mhz
// add a capa 1000 microf between 5V an gnd
// ATMEL ATTINY45 / ARDUINO
//
//                           +-\/-+
//  outB5 yelow to DRO PB5  1|    |08  VCC                        red
//           quartz1   PB3  2|    |07  PB2  (B  2)    outA1 green to DRO
//           quartz2   PB4  3|    |06  PB1  (B  1)    in2 B yelow from encoder
//          black      ground|    |05  PB0  (B  0)    in1 A green from encoder
//                           +----+
#include <avr/io.h>
long int encoder0Pos,encoder0Divide = 0;
const char direction [16] =   {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
const char   slowEncoder [9] = {4,36,0,32,0,4,36,0,32,};
#define in1   0 //PB0  
#define in2   1 //PB1  
#define outA1 2 //PB2  
#define outB2 5 //PB5  
#define mask 27 //011011
byte New,Nnew, Old;
char sign=0;
byte  diviseNew;
byte Divisor=2;
void setup() {
 pinMode(in1, INPUT);
 pinMode(in2, INPUT);
 pinMode(outA1 , OUTPUT);
 pinMode(outB2 , OUTPUT);}
void loop() {
 Nnew=PINB & 3;
   if(New != Nnew){  
                   Old = New;
                   New = Nnew;
                   sign = direction [Old * 4 + New];
                   if (sign){
                           encoder0Pos+= sign;
                           if (!(encoder0Pos&1)){                            
 diviseNew=slowEncoder[(4+sign+(((PINB & 0b000100)>>2)+((PINB & 0b100000)>>4))*sign)];
                                if ((encoder0Divide*Divisor)!=encoder0Pos){
                                    encoder0Divide+= sign;                                                        
                               PORTB &=(mask);
                               PORTB |= (diviseNew);              
                                }                  
                           }
                    }
  }
}


since I give the source it is not for a pseudo protection
I need to set the fuse rstdisbl to 0
Ok BUT
If I set rstdisbl to 0 I cannot load my source ?
Since it work I do not need to reload it
Can someone explain me the order of operation ?
Since I have no timer I can program it with an quartz 16Mhz and put a 20 Mhz for running

So first I download a bootloader external quartz
Then I download my program
Then I change my fuse ?

DrAzzy

#1
Jan 22, 2018, 04:23 pm Last Edit: Jan 22, 2018, 04:24 pm by DrAzzy
Do "Burn bootloader" with external crystal selected (my core should have 20mhz external crystal option)
Compile and upload your program (be sure you're building for 20mhz, not 16)
Use avrdude (or other tool) to change the fuses to set RSTDISBL. Pray that it works.

You can program it just fine with 20mhz crystal too, why wouldn't you be able to?

Keep in mind the limitations of the reset pin as GPIO - this is detailed in the datasheet. IIRC it has significantly weaker pin drivers.
ATtiny core for 841+1634+828 and x313/x4/x5/x61/x7/x8 series Board Manager:
http://drazzy.com/package_drazzy.com_index.json
ATtiny breakouts (some assembled), mosfets and awesome prototyping board in my store http://tindie.com/stores/DrAzzy

rokag3

#2
Jan 23, 2018, 02:39 am Last Edit: Feb 08, 2018, 03:16 am by rokag3
Thank you very much for your answer DrAzzy, I find out that there is a version in 20Mhz  so I did use it

for those like me who never did it before


to set your fuse

IMPORTANT :
Launch DOS terminal with Administrator rights (right click then "run as administrator")


avrdude -c usbtiny -p m8 -C ..\etc\avrdude.conf -b 9600 -v

Read fuses
avrdude -c usbtiny -p m8 -C ..\etc\avrdude.conf -b 9600 -v -U hfuse:r:helloworld.hex -F

in my case DF at this moment I can reload my program reset work  but PB5 is not available

Set RSTDISBL
avrdude -c usbtiny -p m8 -C ..\etc\avrdude.conf -b 9600 -v -U hfuse:w:0x5F:m -F
At this moment I canot reload programs reset did nit work  but PB5 is available


---- hfuse HEX values -----
RSTDISBL enabled : 5F
RSTDISBL enabled : DF


It work
Well in fact I have to check with my scope because it did work a bit strangely, but maybe I have done some stupid cleaning
It work increasing ClockWise but Anticlkwise it decrease then increase  :o  :o
I tend to accuse my software but I like to understand what mean  weaker pin drivers.


rokag3




https://www.tinkercad.com/things/c7hffHDJnX3-copy-of-prototype-encoder-divider/editel
You can test it
If you think that it can go faster tell me
with an attiny45 this can easily be used to read a fast encoder like those you can hack
 from inkjet printer and determine direction of the motor if he slow down or accelerate
even of how much send the position of the encoder and give more time for your your PID to work on your main board

 

Code: [Select]
//vb2.0
//rokag3 2/7/2018
//divider by 2 for a quadrature encoder diviseur par 2 d'encodeur en quadrature
//attiny 85 20mhz to divide by AnotherNumber  you must change this test if (!(encoder0Pos&1))
//and replace it with a test that will determine that your position can be divided by AnotherNumber
it will be a little bit slower
// ********************************************************************************************
//Arduino IDE & Pin Mapping 
// add  2 capacitor 22picof ground to PB3 and PB4 where is the crystal 20mhz
// add a capa 1000 microF between 5V an gnd use this circuit only with high impedance input PB5 (former reset)cannot light up a led 
// ATMEL ATTINY85 / ARDUINO
//
//                              +-\/-+
//in1 A green from encoderPB5  1|    |08  VCC                        red
//       quartz1 (    )   PB3  2|    |07  PB2  (B  2)           in2 A yelow from encoder
//       quartz2 (    )   PB4  3|    |06  PB1  (B  1)           outA1 green to DRO
//        black           ground|    |05  PB0  (B  0)           outB5 yelow to DRO 
//                              +----+
#include <avr/io.h>
long int encoder0Pos =1;
const char direction [16] =  {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
const char slowEncoder [9] = {1,3,0,2,0,1,3,0,2};
const byte Nnewmatrix [64] = {0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
                              2,2,2,2,3,3,3,3,2,2,2,2,3,3,3,3,2,2,2,2,3,3,3,3,2,2,2,2,3,3,3,3};
                              


#define in1  2 //PB2  
#define in2  5 //PB5 
#define outA1 0 //PB0 
#define outB2 1 //PB1 
// #define mask 27 //011011 
byte New,Nnew, Old; 
char sign=0;
byte  diviseNew,test;

void setup() {
 pinMode(in1, INPUT);
 pinMode(in2, INPUT);
 pinMode(outA1 , OUTPUT);
 pinMode(outB2 , OUTPUT);
 
}
void loop() 
{Nnew=Nnewmatrix [test=PINB];
   if(New != Nnew)
   {Old = New; 
    New = Nnew;
    sign = direction [Old * 4 + New];
    encoder0Pos+= sign; 
         if (!(encoder0Pos&1))
         {diviseNew=slowEncoder[(4+sign)+((test&=3)*sign)];
        PORTB |= diviseNew;
        PORTB &= diviseNew;                         
         }
     }









DrAzzy

#4
Feb 07, 2018, 04:20 am Last Edit: Feb 07, 2018, 04:20 am by DrAzzy
I tend to accuse my software but I like to understand what mean  weaker pin drivers.


Much lower current available when using as OUTPUT.

See section 22.6 of datasheet, compare fig 22.19 ~ 22.23 for normal I/O pins to fig 22.24~22.27
 for reset pins (note the different scale)
ATtiny core for 841+1634+828 and x313/x4/x5/x61/x7/x8 series Board Manager:
http://drazzy.com/package_drazzy.com_index.json
ATtiny breakouts (some assembled), mosfets and awesome prototyping board in my store http://tindie.com/stores/DrAzzy

rokag3

Thank you DrAzzy,
This is the main reason why I choose to use port 5(ex reset) in input.

In order to avoid masking/shifting I choose  to use a matrix having all the combinations for the port 2 and 5, this very heavy way to solve the problem is dictated by the choice of favoring the speed, the fact that I have no limitation in memory in this application .

Logically for the applications critic for the speed like an  an encoder you try to spool as fast as possible considering that you have more time to treat the event if you start very early. It is then the longest time needed to treat the problem that determine the fastest frequency you can treat.

To go as fast as possible, you must then try to evaluate the part of the compulsory job you can make in the checking spool

I suppress the test for sign since It is possible to have no adverse effects if processing a sign 0

rokag3

So it work, good enough for the use I have (print a value divide by 2 on a dro for a lathe the dro is made for a 10micron step encode and the new one is a 5 micron step)

It is fast but not as fast as I was expected, If I make very fast acceleration with my hand I can manage to loose steps, if this speed is not possible for the lathe on a linear encoder it is very possible on a rotary encoder

So if someone get an idea to go faster on this program that is already not too slow then I will certainly learn something very interisting

To make your attiny85 able to be reprogrammed
I use thishttps://sites.google.com/site/wayneholder/attiny-fuse-reset it work perfectly
you need
5 resistances of 1k ohms brown black red or brown black black brown
1 NPN transistor like 2N3904
1 arduino uno  and 12 v

rokag3

#7
Feb 23, 2018, 09:38 am Last Edit: Feb 23, 2018, 10:04 am by rokag3
So here is my code for Attiny 85 at 20 mhz to make a quadrature divider.
So easy to do by soft and so hard by hardware (no you cannot just use a divider  :)  )

It can divide by any number from 1 to 127  here I divide the signal by 47  :o

it does not use long integer anymore and of course no  divisions shift or modulo

A nice exercise of coding

Code: [Select]


//v 1.0
//Lucien Lescanne alias rokag3 2/23/2018
//divider by any number  for a quadrature encoder diviseur paR N'IMPORTE QUEL NOMBRE entre 1 et 127 encodeur en quadrature
//attiny 85 20mhz to divide by AnotherNumber  you must change the value of divider,encoder0Pos = here 47;
//
// ********************************************************************************************
//Arduino IDE & Pin Mapping
// add  2 capacitor 22picof ground to PB3 and PB4 where is the crystal 20mhz
// add a capa 1000 microF between 5V an gnd use this circuit only with high impedance input PB5 (former reset)cannot light up a led
// ATMEL ATTINY85 / ARDUINO
//
//                              +-\/-+
//in1 A green from encoderPB5  1|    |08  VCC                        red
//       quartz1 (    )   PB3  2|    |07  PB2  (B  2)           in2 A yelow from encoder
//       quartz2 (    )   PB4  3|    |06  PB1  (B  1)           outA1 green to DRO
//        black           ground|    |05  PB0  (B  0)           outB5 yelow to DRO
//                              +----+
#include <avr/io.h>

const char direction [16] =  {0,-1,1,3,1,5,6,-1,-1,9,10,1,12,1,-1,15};//valid 1 or -1 others value are for debug
const char slowEncoder [9] = {1,3,0,2,0,1,3,0,2};//sequence encoder output
const byte Nnewmatrix [64] = {0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
                              2,2,2,2,3,3,3,3,2,2,2,2,3,3,3,3,2,2,2,2,3,3,3,3,2,2,2,2,3,3,3,3};//this matrix to avoid any shift opeqtion
                              

#define in1  2 //PB2 if you change here you must rerwrite the matrix direction
#define in2  5 //PB5 if you change here you must rerwrite the matrix direction
#define outA1 0 //PB0 if you change here you must rerwrite the matrix slowEncoder
#define outB2 1 //PB1 if you change here you must rerwrite the matrix slowEncoder
 
byte New,Nnew, Old,test; //to hold the value of the port without calling the port
char sign=0;// this give the direction of the encoder
//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
char divider,encoder0Pos = 47;// GIVE THE VALUE YOU WANT HERE the divider must be smaller than 127 or change the type
char divider = 47;// GIVE THE VALUE YOU WANT HERE the divider must be
char encoder0Pos = 47; //smaller than 127 or change the type  (encoder0pos=divider to be in sync)
//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
byte  diviseNew;//quadratic value out

void setup() {
 pinMode(in1, INPUT);
 pinMode(in2, INPUT);
 pinMode(outA1 , OUTPUT);
 pinMode(outB2 , OUTPUT);
 
}
void loop()
{Nnew=Nnewmatrix [test=PINB];//extract the port value in a 2 bits byte without shifts, read the port once per loop to avoid changes during output operation  
 if(New != Nnew)
 {  Old = New;
    New = Nnew;//swapping of the content of port to detemine the direction you must keep trace of the past
    sign = direction [Old * 4 + New]; //determine the direction
    encoder0Pos+= sign;//increment or decrement the counter
    
    if(sign = 1)//the purpose is to avoid modulo  
    {
      if(encoder0Pos>=divider)
         {
        diviseNew=slowEncoder[(4+sign)+((test&=3)*sign)];// calculation of the value for output
        PORTB |= diviseNew;
        PORTB &= diviseNew;
        encoder0Pos=0;  //reset to zero if sign positive    
         }
      else if (encoder0Pos<=0)//if you are concern by safety you must put here the filters for invalid values
         {
        diviseNew=slowEncoder[(4+sign)+((test&=3)*sign)];
        PORTB |= diviseNew;
        PORTB &= diviseNew;
        encoder0Pos=divider; //reset to diviser if sign is considered to be -1
         }
  
      }
 }
}  




https://www.tinkercad.com/things/fVRzQYHgUh1
 

Go Up