Go Down

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

#### rokag3

##### Jan 22, 2018, 03:24 pmLast 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

Then I change my fuse ?

#### DrAzzy

#1
##### Jan 22, 2018, 04:23 pmLast 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.
ATTinyCore for x4/x5/x61/x7/x8/x41/1634/828/x313 megaTinyCore for the megaavr ATtinies - Board Manager:
http://drazzy.com/package_drazzy.com_index.json
ATtiny breakouts, mosfets, awesome prototyping board in my store http://tindie.com/stores/DrAzzy

#### rokag3

#2
##### Jan 23, 2018, 02:39 amLast 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

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

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
I tend to accuse my software but I like to understand what mean  weaker pin drivers.

#### rokag3

#3
##### Feb 07, 2018, 03:40 am

`https://www.tinkercad.com/things/c7hffHDJnX3-copy-of-prototype-encoder-divider/editelYou 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 AnotherNumberit 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 amLast 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)
ATTinyCore for x4/x5/x61/x7/x8/x41/1634/828/x313 megaTinyCore for the megaavr ATtinies - Board Manager:
http://drazzy.com/package_drazzy.com_index.json
ATtiny breakouts, mosfets, awesome prototyping board in my store http://tindie.com/stores/DrAzzy

#### rokag3

#5
##### Feb 07, 2018, 03:14 pm
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

#6
##### Feb 07, 2018, 11:34 pm
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 amLast 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

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 debugconst char slowEncoder [9] = {1,3,0,2,0,1,3,0,2};//sequence encoder outputconst 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//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVchar divider,encoder0Pos = 47;// GIVE THE VALUE YOU WANT HERE the divider must be smaller than 127 or change the typechar 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)//MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMbyte  diviseNew;//quadratic value outvoid 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         }         } } }   `