Fast dividing by 5 and by 10 for uint32_t input data for ATMEGA16A

Go To Last Post
123 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The "{{{{" go to the nested if checks in the thing to trim leading zeros; each of those lines has a { but no }. Eww.

 

 

Having looked at the various forms of this, I think that optimizing division by ten is not nearly as useful as doing division by 100, and then having a lookup table for %100 to pairs of digits. Of course, you still have to make the division by 100 faster, but 100 bytes of flash for hex-packed lookup tables (or 200 for ASCII lookup tables) seems pretty decent. So, you just have a [200]uint8_t in flash, and [69*2] is 0x36, and [69*2+1] is 0x39, and hey, there you go.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

rpz3598 wrote:

  while (R >=0x2710){ Q++;  R-=0x2710; }
  digits[0]= (uint8_t) Q +0x30;
  Q = 0;
  while (R >=0x03e8 ){ Q++; R-=0x03e8 ; }
  digits[1] = (uint8_t) Q +0x30;
  Q = 0;
  while (R >=0x0064) { Q++; R -=0x0064;}
  digits[2] = (uint8_t) Q +0x30;
  Q = 0;
  while (R >=0x000A  ) { Q++; R -=0x000A ;  }
  digits[3] = (uint8_t) Q +0x30;
  digits[4]=  (uint8_t) R +0x30;

Is this an obsfucation contest entry? Why would you give the literal constants in hex (0x2710, 0x3E8, 0x64, 0x0A) ? Most readers would be happier seeing 10000, 1000, 100, 10 wouldn't they for a decimal conversion? By the same token why use 0x30 when '0' tells the reader much more about the intention of the code. I also realise that Q and R are quotient and remainder but why limit to single letter variables?

  while (remainder >= 10000) {
      quotient++;  
      remainder -= 10000; 
  }
  digits[0] = (uint8_t) quotient + '0';
  quotient = 0;
  while (remainder >= 1000 ) {
      quotient++; 
      remainder -= 1000; 
  }
  digits[1] = (uint8_t) quotient + '0';
  quotient = 0;
  while (remainder >= 100) { 
      quotient++; 
      remainder -= 100;
  }
  digits[2] = (uint8_t) quotient + '0';
  quotient = 0;
  while (remainder >= 10  ) { 
      quotient++; 
      remainder -= 10;
  }
  digits[3] = (uint8_t) quotient + '0';
  digits[4] = (uint8_t) remainder + '0';

is exactly the same code, produces the exact same opcodes but is much more readable for the maintainer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Alternative editions of the ATMEGA8A DDS  with TV (som problems with timer 0, timer2 noise , you can rebuild it for ATMEGA16A). Using DDS Soir compatible pinouts and circuit (alt building).

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How to add PWM (menu mode 8 ) with frequncy , DCy (0-99%), Order (1-6)  control for OC1A?

 


/*
0 do nothing, no blinking
1 set Order
2 set freq
3 set DCy
4 nothing , as if  mod1= 0
*/
uint8_t mod1=0;
uint8_t Order=0; 

void PWMBlinkOff();
void SelectPWMFreqOrderBlink();
void SelectPWMHSFreqBlink();
void SelectPWMDutyCycle();

void IncOrderPWM(){
Order++;  //fix if order =0 , then order =1 or off
if(Order>6){ Order=1;}
if(Order==0){ Order=1;}
} 

void DecOrderPWM(){
if(Order==0){ Order=1; }
Order--;  //fix if order =0 , then order =1 or off
if(Order<1){ Order=6; }
}

void IncFreqPWM();   //insert code
void DecFreqPWM();  //insert code 

void IncDCyPWM();    //insert code
void DecDCyPWM();   //insert code 

void SelectPWMSubmenu()
{
if (mod1==0) {  PWMBlinkOff();  return; }
if (mod1==1){   SelectPWMFreqOrderBlink(); return ;  } //1...6  (1-1...10Hz, 2 -10...100 Hz, ... 6-100...1000 kHz  by Up,Down )
if (mod1==2){   SelectPWMHSFreqBlink(); return ; }  //(1,2...10  step 1 , 1 after 10 )*10^Order  by Up,Down
if (mod1==3){   SelectPWMDutyCycle(); return ; } //0-99% , step 1%  by Up,Down
}

void OnButtonRightPWM()
{
if(mod1==0){ mod1++ ; }
if(mod1>=4){ mod1=0 ;  return; }
SelectPWMSubmenu();
//exit, update menu
}

void OnButtonLeftPWM()
{
if(mod1==0){ mod1=3 ;  return; } //fix
if(mod1>=1){ mod1-- ; }
SelectPWMSubmenu();
//exit, update menu
}

void  OnButtonUpPWM()
{
 if(mod1==1) { IncOrderPWM(); return ; }
 if(mod1==2) { IncFreqPWM(); return ; }
 if(mod1==3) { IncDCyPWM(); return ; }
return;
}

void  OnButtonDownPWM()
{
 if(mod1==1) { DecOrderPWM(); return ; }
 if(mod1==2) { DecFreqPWM(); return ; }
 if(mod1==3) { DecDCyPWM(); return ; }
return;
}

/*
add PWM menu  parsers
...
//if  right button pressed
if (mode==8) {  OnButtonRightPWM();   /*...*/  return; }  //fix
...
//
//if  left button pressed
if (mode==8) {  OnButtonLeftPWM();   /*...*/  return; }  //fix
...

//if Up button pressed
if (mode==8) {  OnButtonUpPWM();   /*...*/  return; }  // fix 

...
//if Down button pressed
if (mode==8) {  OnButtonDownPWM();   /*...*/  return; }  // fix
...
add  PWM on/off menu parser
*/

For ATMEGA8A may be  memory overflow (if not use assembler). 

Last Edited: Wed. Jun 16, 2021 - 03:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

#define F_CPU  16000000UL

#include <stdio.h>
#include <stdlib.h>
//#include <stdbool.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <inttypes.h>
// #include "lcd_lib.h"
#include <math.h>










  inline void pwm_stop()
{
	TCCR1A = 0;
	TCCR1B = 0;
	PORTB &= ~(1<<PB1);
	DDRB&= ~(1<<PB1);
}

 /*

  uint32_t  div_const( uint32_t N , uint32_t D  )
{
uint32_t Q=0;
uint32_t R=F_CPU ; //(uint32_t )N;      //fix
while(R>=D){ Q++; R-=D; }
//printf ("\nN=%ld R=%ld  Q=%ld  D=%ld",N,R,Q,D);


return  R;
}

    */
uint32_t  div_const(   uint32_t D  )
{
uint32_t Q=0;
uint32_t R=16000000UL ; //(uint32_t )N;      //fix
while(R>=D ){Q++;  R-=D ; }
//printf ("\nN=%ld R=%ld  Q=%ld  D=%ld",N,R,Q,D);


return  (uint32_t)Q;
}

uint32_t  div_25( uint32_t N   )
{
uint32_t Q=0;
uint32_t R=(uint32_t ) N;
while(R>=25UL){ Q++; R-=25UL; }
//printf ("\nN=%ld R=%ld  Q=%ld  ",N,R,Q );
return  (uint32_t)Q;
}

void pwm_start(uint32_t freq, uint8_t dcy)
{
uint32_t period;	
PORTB &= ~(1<<PB1);
DDRB |= (1<<PB1);	
period =(uint32_t)div_const((uint32_t) freq)-1;  // (F_CPU/freq) - 1;  //fix    15999
TCCR1A = (1<<COM1A1) |(1<<WGM11);
//fast PWM

    /*
      WGM mode 14 = Fast PWM mode :
fOC1APWM = fclk=IO / ( N * (1 + TOP))
N = 1 - prescaler
TOP = ICR1 = 532.

    */


if(freq > 130)
{				
ICR1 =  (uint16_t)period;	
//if(SG.mode==6){ OCR1A =  (uint16_t)(period/2); }  //fix
//else /*if(SG.mode==8) */  {
//OCR1A = (uint16_t)(period * dcy / 100);     //15999*50/100 7999
//OCR1A =  (uint16_t)(ICR1 /2);
 OCR1A =(uint16_t)div_25(((uint32_t)(ICR1 * dcy) >>2) );
//}
TCCR1B =(1<<WGM13)  | (1<<WGM12) |(1<<CS10); //??? ????????	
}//fast PWM, mode 14, prescaler=1
 else
 {
 period =period>> 8;
 ICR1 = (uint16_t) period;	
//  OCR1A = (uint16_t)(period * dcy / 100);
OCR1A =(uint16_t)div_25(((uint32_t)(ICR1 * dcy)>>2) );	
 TCCR1B =(1<<WGM13)  | (1<<WGM12) | (1<<CS12); // ???????? 256
 }//fast PWM, mode 14, prescaler=256	

	
}





/*********************/

//const uint8_t welcomeln1[] PROGMEM ="AVR LCD DEMO\0";
int main(void)
{
//Initialize



 // Timer1_StartPWMFastPWM14Icr();
  pwm_start((uint32_t)30000,50)  ;  //works if ICR1=532

 while(1){ ; }


return 0;	

}





How to rebuild for freq=1Hz(1000Hz)...100000 Hz?

Works is ICR=532 (f=30000 Hz) , if 20 kHz, 40 kHz, 50 kHz  problem with duty cycle. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define F_CPU  16000000UL

#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <inttypes.h>
 //#include "lcd_lib.h"
#include <math.h>

    void pwmInit (void)
{
  PORTB &= ~(1<<PB1);
  DDRB |= (1<<PB1);	

TCCR1B = (1 << CS11);
//TOP= 32:
ICR1 = 32;
// for DCy=50%
OCR1A = 16;
//OC1A = 0 if  TCNT1= OCR1A:
TCCR1A = (1 << COM1A1);
// Phase and Frequency Correct, mode 8
TCCR1B |= (1 << WGM13);
//Iano?ieea ii?ee OC1A eae auoia:
//DDRB |= (1 << PB1);
}

/*********************/

//const uint8_t welcomeln1[] PROGMEM ="AVR LCD DEMO\0";
int main(void)
{
//Initialize

 // Timer1_StartPWMFastPWM14Icr();
//  pwm_start((uint32_t)80000,50)  ;
  pwmInit ()   ;
 while(1){ ; }

return 0;	

}

Is this program correct? Is OCR1A  and ICR1  8 bit in the  mode 8 (ICR) and mode 9(OCR1A) (for problem in the VMLAB for mode 8 , mode 9 of WGM  for ATMEGA8 )? 

How to create program for  PWM control for F=1Hz(1kHz)-100 kHz , DutyCycle=1..99% (with DCy error < +/- 1 % , for F=16 MHZ)?

In the VMLAB 3.15 no signal  on the PB1 . 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

WOW this must be the slowest (3 months) divide code ever! devil

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

but thidis a compact code . May be more optimal . Some codes for SimulIDE (problem    with OC1A        in the SimulIDE_0.4.14-SR4_Win32, fixed in the     SimulIDE_0.4.15-SR1_Win64  , but with some bugs    , fixed problem with diodes  )

Attachment(s): 

Last Edited: Sat. Jun 19, 2021 - 09:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My programs of the DDS    with application of some of the  subroutines  ,models for  SimulIDE_0.4.15-SR1_Win64 (alt builds for Soir's  DDS ( https://sxem.org/2-vse-stati/24-... ) ).   May be with some bugs, but works .

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


void Timer1_Start(uint8_t FkHz)
{
 



DDRB|=0b00000010;

//TCCR1A=0x40;  //Output compare toggles OC1A pin
//  WGM13=0, WGM12=1; CS12 =0 CS11=0,CS10=1 (N=1)
 /*
if (FkHz==0)
{

//mode 12 , CTC,ICR , no toogles, DCy=50%
  ICR1=1;
  OCR1A=0;
  TCCR1A = (1<<COM1A1) |(0<<WGM11);
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
}
else 
{*/
//mode 4 CTC, toggle

OCR1A= pgm_read_word(OCR1AArray+(uint16_t)FkHz);
 TCCR1A = (0<<COM1A0)|(1<<COM1A0) | (0<<WGM11)|(0<<WGM10)    ;
 if(FkHz>=HSWITHPRESC1) {  TCCR1B= (1<<WGM12)| (1<<CS11); } else {  TCCR1B= (1<<WGM12)| (1<<CS10);  }	
 //}
	
}

void Timer1_Stop(void){ TCCR1B=0x00;  TCCR1A =0x00;            } //timer off

works on 8 MHz (OCR1A=0) in toogle mode  with ATMEGA8A , but problem in the emulator (ATMEAGA8), gets zero .

 

My program for ATMEGA8A , works   . For Atmel Studio 7 

ALT+F7(project)  proj. name Properties ->Toolchain->AVR/GNU Linker - > add segments -> Flash segments 
 
MySection1=0x0D00
MySection2=0x0D80
MySection3=0x0E00
MySection4=0x0E80
MySection5=0x0F00
MySection6=0x0F80

 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


/*
 void  inline   Parser1( uint16_t  period,  uint8_t dcy   )
{
 uint16_t res1=0;
 asm volatile(
       
                  
 	"1:  mov r16, %A1 ; L" "\n\t"
	" mov r17,   %B1 ; H"  "\n\t"

	" mov r13, %2 " "\n\t"
                  " clr r20 ; mul  r17, r14;  ; ah * bh ;" "\n\t"
	" clr r21 ; movw  r20,  r0  " "\n\t"                	
	" mul  r16, r13   ; al * bl; " "\n\t"
	" movw r18,  r0  " "\n\t"
	" mul  r17, r13   ; ah * bl; " "\n\t"
   " clr  r13" "\n\t"
   " add  r19, r0 " "\n\t"
   " adc  r20, r1 " "\n\t"
   " adc  r21, r13 " "\n\t"

     "clr   R26 " "\n\t"

     "clr r25 ; begin dividing by 100 sub " "\n\t"
     "ldi r24, 0x64 ;" "\n\t"

     "clr   R16  " "\n\t"
     "clr   R17 " "\n\t"
     "clr   r22 " "\n\t"
     "clr   r23 " "\n\t"

     "2: clc" "\n\t"
     " cp    R18, R24   ; if {r21:r20 ; r19:18} < 100 , exit  " "\n\t"
      "cpc   R19, R25  " "\n\t"
      "cpc   R20, R25  " "\n\t"
      "cpc   R21, R25  " "\n\t"
      " brlo    3f" "\n\t"


     "clc" "\n\t"
     "ldi   r22, 1 "  "\n\t"
     "add   R16, R22 ; " "\n\t"
     "adc   R17, R23 ; Result++ " "\n\t"
     "clc" "\n\t"

     "sub   R18, R24 ; R-=100 " "\n\t"
     "sbc   R19, R25 ; " "\n\t"
     "sbc   R20, R25 "   "\n\t"
     "sbc   R21, R25 "   "\n\t"
     "clc" "\n\t"
     "rjmp  2b " "\n\t"

     "3: " "\n\t"
      "clc" "\n\t"
     "  mov %A0, r16; " "\n\t"
     " mov %B0,  r17; " "\n\t"

               :  "=r"(res1) 
               :  "r"(period),"r"(dcy) 
    
);

 OCR1A=res1;
 return  ;
}	


*/


 

inline void pwm_stop(void){ TCCR1A = 0; TCCR1B = 0; HSPORT &= ~(1<<HS ); HSDDR &= ~(1<<HS) ; }

void pwm_start1(uint8_t freq, uint8_t ord, uint8_t dcy)
{
HSPORT  &= ~(1<<HS);
HSDDR |= 1<<HS;
TCCR1A = (1<<COM1A1) |(1<<WGM11);

if(ord==0) { ICR1=(uint16_t)pgm_read_word(PWM_0ICR+(uint16_t) freq ) ;  }
if(ord==1) { ICR1=(uint16_t)pgm_read_word(PWM_1ICR+(uint16_t) freq ) ; }
if(ord==2) { ICR1=(uint16_t)pgm_read_word(PWM_2ICR+(uint16_t) freq ) ; }
if(ord==3) { ICR1=(uint16_t)pgm_read_word(PWM_3ICR+(uint16_t) freq ) ; }
if(ord==4) { ICR1=(uint16_t)pgm_read_word(PWM_4ICR+(uint16_t) freq ) ; }
if(ord==5) { ICR1=(uint16_t)pgm_read_word(PWM_5ICR+(uint16_t) freq ) ; }
//ICR1=53332;
 	
// Parser1( ICR1,  dcy ); //=(dcy*period)/100+
//uint32_t period= (ICR1*dcy);
//period/=100;
 
dcy=50;
/*
   int32_t R=(int32_t)((uint16_t)ICR1*(uint8_t)dcy);
 
 if((dcy&0x01)!=0) {  R+= ( uint32_t)(ICR1<<0) ; }
 if((dcy&0x02)!=0) {  R+= ( uint32_t)(ICR1<<1) ; } 
 if((dcy&0x04)!=0) {  R+= ( uint32_t)(ICR1<<2) ; } 
 if((dcy&0x08)!=0) {  R+= ( uint32_t)(ICR1<<3) ; } 

 if((dcy&0x10)!=0) {  R += ( uint32_t)(ICR1<<4) ; } 
 if((dcy&0x20)!=0) {  R+= ( uint32_t)(ICR1<< 5 ); }  
 if((dcy&0x40)!=0) {  R += ( uint32_t)(ICR1<<6) ; } 
 if((dcy&0x80)!=0) {  R += ( uint32_t)(ICR1<<7) ; } 
 
uint16_t Q1=0;
while((int32_t)R >=0x00000064 ){ Q1++;   R -=0x00000064   ; }
OCR1A=Q1;
*/
 OCR1A=(uint16_t)(ICR1>>1);


if((ord<2)||((ord==2)&&(freq<2)))
{
   //period /= 256;
 TCCR1B =(1<<WGM13)  | (1<<WGM12) | (1<<CS12);// N=256
}
else
{
 TCCR1B =(1<<WGM13)  | (1<<WGM12) |(1<<CS10);//N=1
}
}

Problem with registers after turn on and OCR1A obtaining : data mapping error (for example   for 300 kHz , DCy error  for 50 % ), temporary DCy set to 50 % 

Problem may be fixed if  use only assembler and manually define  registers  and stack . 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
while((int32_t)R ...   //may be with carry error ,.
//if uint32_t  and with error , if store this data in the registers and problem   
//use assembler 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But code with asm equivalent of the 

uint16_t Q1=0;
while((int32_t)R >=0x00000064 ){ Q1++;   R -=0x00000064   ; }
OCR1A=Q1;

may be compact and simple (if fic carry problem for long types ) .

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Test program for dividind . If I use it  in the hsgen.h,  problem with stack, registry mappings, push/pop is not fixed. 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

void  static inline   Parser1( uint16_t  period,  uint8_t dcy   )
{
 
 //ICR1=period;
 uint16_t res1=0;
 asm volatile(
 
   "1:   push r16" "\n\t"
   "    push r17" "\n\t"
     "  in r16, __SREG__" "\n\t"
    "  push r16" "\n\t"
   "     push r18" "\n\t"
   "    push r19" "\n\t"
   "     push r20" "\n\t"
   "     push r21" "\n\t"
   "     push r0" "\n\t"
   "     push r1" "\n\t"
 
  " mov r16, %A1 ; L" "\n\t"
 " mov r17,   %B1 ; H"  "\n\t"
 
 " mov r13, %2 " "\n\t"
   " clr r20 ; mul  r17, r14;  ; ah * bh ;" "\n\t"
 " clr r21 ; movw  r20,  r0  " "\n\t"                   
 " mul  r16, r13   ; al * bl; " "\n\t"
 " movw r18,  r0  " "\n\t"
 " mul  r17, r13   ; ah * bl; " "\n\t"
 
   " clr  r13" "\n\t"
   " add  r19, r0 " "\n\t"
   " adc  r20, r1 " "\n\t"
   " adc  r21, r13 " "\n\t"
 
     "clr r13 ; begin dividing by 100 sub " "\n\t"
 
 
     "clr   R16  " "\n\t"
     "clr   R17 " "\n\t"
 
 
     "2: clc" "\n\t"
     " cpi    R18, 0x64  ; if {r21:r20 ; r19:18} < 100 , exit  " "\n\t"
      "cpc   R19, R13  " "\n\t"
      "cpc   R20, R13  " "\n\t"
      "cpc   R21, R13  " "\n\t"
      " brlo    3f" "\n\t"
 
 
     "sec" "\n\t"
     "adc   R16, R13 ; " "\n\t"
     "adc   R17, R13 ; Result++ " "\n\t"
     "clc" "\n\t"
 
     "subi   R18, 0x64 ; R-=100 " "\n\t"
     "sbci   R19, 0x00 ; " "\n\t"
     "sbci   R20, 0x00 "   "\n\t"
     "sbci   R21, 0x00 "   "\n\t"
     "clc" "\n\t"
     "rjmp  2b " "\n\t"
 
     "3: " "\n\t"
      "clc" "\n\t"
     "   mov %A0, r16; " "\n\t"
      "  mov %B0,  r17; " "\n\t"
 
 
     " pop r1" "\n\t"
     " pop r0" "\n\t"
      " pop r21" "\n\t"
       "pop r20" "\n\t"
       "pop r19" "\n\t"
       "pop r18" "\n\t"
     " pop r16" "\n\t"
     " out __SREG__, r16" "\n\t"
      "pop r17" "\n\t"
      "pop r16" "\n\t"
 
               :   "=r"(res1)
               :  "r"(period),"r"(dcy)
               : "r0","r1","r13", "r16","r17","r18","r19","r20","r21",  "cc","memory"
 
 
);
  OCR1A=res1; 
      // uint8_t i=0;
 
 return  ;
}






 


 

inline void pwm_stop(void){ TCCR1A = 0; TCCR1B = 0; HSPORT &= ~(1<<HS ); HSDDR &= ~(1<<HS) ; }

void pwm_start1(uint8_t freq, uint8_t ord, uint8_t dcy)
{
HSPORT  &= ~(1<<HS);
HSDDR |= 1<<HS;
TCCR1A = (1<<COM1A1) |(1<<WGM11);

if(ord==0) { ICR1=(uint16_t)pgm_read_word(PWM_0ICR+(uint16_t) freq ) ;  }
if(ord==1) { ICR1=(uint16_t)pgm_read_word(PWM_1ICR+(uint16_t) freq ) ; }
if(ord==2) { ICR1=(uint16_t)pgm_read_word(PWM_2ICR+(uint16_t) freq ) ; }
if(ord==3) { ICR1=(uint16_t)pgm_read_word(PWM_3ICR+(uint16_t) freq ) ; }
if(ord==4) { ICR1=(uint16_t)pgm_read_word(PWM_4ICR+(uint16_t) freq ) ; }
if(ord==5) { ICR1=(uint16_t)pgm_read_word(PWM_5ICR+(uint16_t) freq ) ; }
//ICR1=53332;
 	
  Parser1( ICR1,  dcy ); 
 
if((ord<2)||((ord==2)&&(freq<2)))
{
   //period /= 256;
 TCCR1B =(1<<WGM13)  | (1<<WGM12) | (1<<CS12);// N=256
}
else
{
 TCCR1B =(1<<WGM13)  | (1<<WGM12) |(1<<CS10);//N=1
}
}

Fixed (stack, memory clobbering string ), but may be some problem with stack .

 

Exampe in the attach (may be with some  bugs , problem of  DCy tolerance ( rounding OCR1A, normal for this  processor) for some frequencies  ).

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But problem is not fixed  in the real ATMEGA8A-PU ( "-" -problem , if DCy=50%  )


/*

//period=(F_CPU/freq) - 1
//ICR1 = (uint16_t)period;
//    if(freq > 130) period /= 256;  change  prescaler
// OCR1A=  (uint16_t)(period * d / 100);	
5
1000000	15	+
900000	16.7 	+
800000	19	+
700000	21.8 	+
600000	25.6          +
500000	31	+
400000	39	+
300000	52.3           +
200000	79	+
100000	159            -
159,79,52,39,31,25,21,19,17,15

100,200,300,400,500,600,700,800,900,1000 kHz	
4 		
100000	159	-
90000	176.7        -	
80000	199	- 
70000	227.5 	 - 
60000	265.6 	-
50000	319	-
40000	399	-
30000	532.3 	-
20000	799	-
10000	1599         -
1599,799,532,399,319,265,227,199,176,159

10,20,30,40,50,60,70,80,90,100 kHz	
3  	
 	
10000	1599	-
9000	1776.7 	-
8000	1999	-
7000	2284.7 	-
6000	2665.6 	-
5000	3199	-
4000	3999	-
3000	5332.3 	-
2000	7999	-
1000	15999	-
15999,7999,5332,3999,3199,2665,2285,1999,1777,1599

1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 kHz

2	
	
1000	15999	;62.5 - for period/256 
900	17776.7 	;69.4-
800	19999	;78.1-
700	22856.1 	;89.2-
600	26665.6 	;104.1-
500	31999	;124.9-
400	39999	;156.2-
300	53332.3 	;208.3-
200	79999	;312.4 // use period/256+
100	159999	;624.9 // use period/256+

624,312,   53332,39999,31999,26665,22856,19999,17777,15999

100,200,300,400,500,600,700,800,900,1000 Hz	


1	
100	159999	;624.9 +// use period/256
90	177776.7 	;694.4+
80	199999	;781.2+
70	228570.4 	;892.8-
60	266665.6 	;1041.6-
50	319999	;1249.9-
40	399999	;1562.49-
30	533332.3 	;2083.3-
20	799999	;3124.9-
10	1599999	;6249.9-
6249,3125,2083,1562,1250,1041,893,781,694,624

10,20,30,40,50,60,70,80,90,100 Hz

0
10	1599999	;6249.9-
9	1777776.7  ;6944.4;-
8	1999999	 ;7812.49-
7	2285713.2 ;8928.56-
6	2666665.6;10416.6;-
5	3199999	;12499.9;-
4	3999999	;15624.9;-
3	5333332.3 ; 20833.3-
2	7999999	;31249.9-
1	15999999	;62499.9;-

62500,31250,20833,15625,12450,10416,8928,7812,6944,6249

1,2,3,4,5,6,7,8,9,10 Hz
*/

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


void  static inline   Parser1( uint16_t  period,  uint8_t dcy   )
{



 asm volatile(

   "1:   push r16" "\n\t"
   "    push r17" "\n\t"
     "  in r16, __SREG__" "\n\t"
    "  push r16" "\n\t"
   "     push r18" "\n\t"
   "    push r19" "\n\t"
   "     push r20" "\n\t"
   "     push r21" "\n\t"
   "     push r0" "\n\t"
   "     push r1" "\n\t"
   "     push r13" "\n\t"
   "     push r12" "\n\t"

 " mov r16, %A0 ; L" "\n\t"
 " mov r17, %B0 ; H"  "\n\t"

      "   out %3, r17; " "\n\t"
      "   out %2, r16; " "\n\t"


  " mov r13, %1 " "\n\t"
 " clr r20 ; mul  r17, r14;  ; ah * bh ;" "\n\t"
 " clr r21 ; movw  r20,  r0  " "\n\t"
 " mul  r16, r13   ; al * bl; " "\n\t"
 " movw r18,  r0  " "\n\t"
 " mul  r17, r13   ; ah * bl; " "\n\t"

   " clr  r13" "\n\t"
   " add  r19, r0 " "\n\t"
   " adc  r20, r1 " "\n\t"
   " adc  r21, r13 " "\n\t"

     "clr r13 ; begin dividing by 100 sub " "\n\t"
     "ldi r16,0x01  " "\n\t"
     "mov r12,r16  " "\n\t"
     "clr   R16  " "\n\t"
     "clr   R17 " "\n\t"


     "2: clc" "\n\t"
     "clr r13" "\n\t"
     " cpi   R18, 0x64  ; if {r21:r20 ; r19:18} < 100 , exit  " "\n\t"
      "cpc   R19, R13  " "\n\t"
      "cpc   R20, R13  " "\n\t"
      "cpc   R21, R13  " "\n\t"
      " brlo    3f" "\n\t"

     "clc" "\n\t"
     "add   r16, r12;   " "\n\t"
     "adc   R17, r13 ; " "\n\t"
     "clc" "\n\t"

     "subi   R18, 0x64 ; R-=100 " "\n\t"
     "sbci   R19, 0x00 ; " "\n\t"
     "sbci   R20, 0x00 "   "\n\t"
     "sbci   R21, 0x00 "   "\n\t"
     "clc" "\n\t"
     "rjmp  2b " "\n\t"

     "3: " "\n\t"
      "clc" "\n\t"

      "   out %5, r17; " "\n\t"
      "   out %4, r16; " "\n\t"

      " pop r12" "\n\t"
      " pop r13" "\n\t"
     " pop r1" "\n\t"
     " pop r0" "\n\t"
      " pop r21" "\n\t"
       "pop r20" "\n\t"
       "pop r19" "\n\t"
       "pop r18" "\n\t"
     " pop r16" "\n\t"
     " out __SREG__, r16" "\n\t"
      "pop r17" "\n\t"
      "pop r16" "\n\t"

               :
               :  "r"(period),"r"(dcy), "I" (_SFR_IO_ADDR(ICR1L)) ,  "I" (_SFR_IO_ADDR(ICR1H)) ,"I" (_SFR_IO_ADDR(OCR1AL))  ,"I" (_SFR_IO_ADDR(OCR1AH))
               : "r0","r1","r12","r13"  ,"r16","r17","r18","r19","r20","r21" , "cc","memory"


);
   //, "I" (_SFR_IO_ADDR(OCR1A))
      // uint8_t i=0;

 return  ;
}

#define HSPORT PORTB
#define HS PB1
#define HSDDR DDRB
void pwm_start1(uint8_t freq, uint8_t ord, uint8_t dcy)
{
HSPORT  &= ~(1<<HS);
HSDDR |= 1<<HS;
TCCR1A = (1<<COM1A1) |(1<<WGM11);
uint16_t periodval=0x0001;
if(ord==0) { periodval=(uint16_t)pgm_read_word(PWM_0ICR+(uint16_t) freq ) ;  }
if(ord==1) { periodval=(uint16_t)pgm_read_word(PWM_1ICR+(uint16_t) freq ) ; }
if(ord==2) { periodval=(uint16_t)pgm_read_word(PWM_2ICR+(uint16_t) freq ) ; }
if(ord==3) { periodval=(uint16_t)pgm_read_word(PWM_3ICR+(uint16_t) freq ) ; }
if(ord==4) { periodval=(uint16_t)pgm_read_word(PWM_4ICR+(uint16_t) freq ) ; }
if(ord==5) { periodval=(uint16_t)pgm_read_word(PWM_5ICR+(uint16_t) freq ) ; }
//periodval=0x000F;
 	
 Parser1( periodval,  dcy ); //=(dcy*period)/100+


if((ord<2)||((ord==2)&&(freq<2)))
{
   //period /= 256;
 TCCR1B =(1<<WGM13)  | (1<<WGM12) | (1<<CS12);// N=256
}
else
{
 TCCR1B =(1<<WGM13)  | (1<<WGM12) |(1<<CS10);//N=1
}
}

program for debug . Fixed problem with inc counter  . Fix problem with coefficients and prescaler values .

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Test   version (alt. build) for ATMEGA8A(source  circuit from https://sxem.org/2-vse-stati/24-... with patches  ) with PWM (1-99%, mode 15 3*5 frequencies),  HF out, exponential, sinus, triangle, sawtooth, rev. sawtooth, square signals . 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm honestly very confused by all this PWM stuff and don't see what it has to do with the "fast divide by 5 or 10" question.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 #include <stdio.h>
 #include <stdint.h>
 #include <math.h>
/*
uint16_t  divs1000b(uint32_t n) {
   uint32_t  q, r, t;

   n = n + (n>>31 & 999);
   t = (n >> 7) + (n >> 8) + (n >> 12);
   q = (n >> 1) + t + (n >> 15) + (t >> 11) + (t >> 14) + (n >> 26) + (t >> 21);
   q = q >> 9;
   r = n - q*1000;
   return (uint16_t )     (q + ((r + 24) >> 10));
// return q + (r > 999);

}
*/

//707=0b 0000 0010 1100 0011
//n =n+(n<<1)+(n<<6)+(n<<7)+(n<<9);

 //n=(uint32_t) (n>>3) - (n>>5) + (n>>7) - (n>>9) + (n>>11) - (n>>13) + (n>>15)  - (n>>17) + (n>>19) - (n>>21) + (n>>23) - (n>25) + (n>>27)  - (n>>29) + (n>>31);
 //n=(uint32_t) (n>>3) - (n>>5) + (n>>7) - (n>>9) + (n>>11) - (n>>13) + (n>>15)  - (n>>17) + (n>>19) - (n>>21) + (n>>23) - (n>25) + (n>>27)  - (n>>29) + (n>>31);
 //q=(uint32_t) (n>>3) - (n>>5) + (n>>7) - (n>>9) + (n>>11) - (n>>13) + (n>>15)  - (n>>17) + (n>>19) - (n>>21) + (n>>23) - (n>25) + (n>>27)  - (n>>29) + (n>>31);   

  // q=(uint32_t)(((uint32_t)n * (uint32_t)0xCCCD) >> 16) >> 3;
  // q=(uint32_t) (((uint32_t)q * (uint32_t)0xCCCD) >> 16) >> 3;
 //  q=(((uint32_t)q * (uint32_t)0xCCCD) >> 16) >> 3;

uint16_t  mul707_divu1000b(uint32_t n) {
  uint32_t q, r, t;
//n*=707
   t=(uint32_t)n+(n<<1);  //temporary
   n=(uint32_t)t+(t<<6)+(n<<9); //3n+(3n<<6)+(n<<9)  

   // return (( n>>2) + ( n>>8) + (( n>>1) + ( n>>5) + ( n>>8) + ( n>>11) + ( n>>12) + ( n >>14) + ( n >> 15)) >> 8) >>8  ;

  // q=(uint32_t) ((((uint32_t)n * (uint32_t)0xCCCD) >> 16) >> 3);
  // q=(uint32_t) (((uint32_t)q * (uint32_t)0xCCCD) >> 16) >> 3;
  // q=(((uint32_t)q * (uint32_t)0xCCCD) >> 16) >> 3;

//   return (uint16_t )q  ;//result
//dividing by 1000
//}

   // t = (n >> 7) + (n >> 8) + (n >> 12);
   t=(n>>7) ; //7
   t+=(t>>1)+(t>>5); //n>>8 + n>>12
   //t+=(n>>12);//12   =(n>>7)>>5
   q = (n>>1)+t+(n>>15)+(t>>11)+(t>>14);
   q = q>>9;
    //r=n-q*1000   //n+q*24-q*1024
    //return q + ((r + 24) >> 10);
   r=(uint32_t)n+24   ;
   q<<=3;  //q*8        6
   r+=q+q+q; //3*q*8=q*24
   q<<=6; //<<10      6
   r-=q; //(q<<10); //3+1+6
   q+=r ;   //q
   q>>=10;
   return (uint16_t )q  ;//result
}
//0011 1110 1000
//1000

//a=(x<<3)+(x<<5)+(x<<6)+ (x<<7)+ (x<<8)+ (x<<9)

int main() {
   int n;
   uint32_t n1;
   uint16_t q1;

for (int n2=0;n2<=1023;n2++)
{
  q1 = mul707_divu1000b(n2);
  printf("\n %ld n1=%ld  q1=%ld",n2,(int)707*n2,(int)q1  );
  if(q1!=(uint16_t)(707*n2/1000  ))  {printf(" *******"); }

}

return 0;
}

Scalling result =0.707*ADCW (for pi16f676 or other processors, for example ).

Modified  code from  Hacker's Delight 2nd Edition by Henry S Warren, Jr. 

Prototype

/* Code below uses 1/1000 = 0.0000 0000 0100 0001 1000 1001 0011 0111.
20 ops including two multiplies, or 29 elementary ops. 0 <= r <= 6292.
Not in book. */

unsigned divu1000a(unsigned n) {
   unsigned q, r, t;

   t = n - (n >> 6) - (n >> 3);
   q = (n >> 10) + (n >> 16) + (n >> 17) + (n >> 21) + (n >> 24) +
       (t >> 26);
   r = n - q*1000;            // 0 <= r <= 6292.
   return q + (4195*r >> 22); // Returning q + r/1000.
// {int t = r + (r << 1);     // Alternative showing
// t = t + (t << 5);          // expansion of multipli-
// t = t + (r << 12);         // cation by 4195.
// return q + (t >> 22);}
}

/* Code below uses 512/1000 = 0.1000 0011 0001 0010 0110 1110 1001 0111.
19 ops including one multiply, or 23 elementary ops. 0 <= r <= 1181. */

unsigned divu1000b(unsigned n) {
   unsigned q, r, t;

   t = (n >> 7) + (n >> 8) + (n >> 12);
   q = (n >> 1) + t + (n >> 15) + (t >> 11) + (t >> 14);
   q = q >> 9;
   r = n - q*1000;
   return q + ((r + 24) >> 10);
// return q + (r > 999);
}

 

Last Edited: Sun. Nov 21, 2021 - 07:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//modifyed Microchip AN526 alg.  

/*
 H       ;   T     ;  O          ;   B
  -        ;   -      ;  -            ;   1010 0010  ;  162
  -        ;   -      ;   xxx1    ;   010   0010  ;  <<#1
  -        ;   -      ;   xx10     ;   10   0010    ;  <<#2
  -        ;   -      ;   x101    ;  0   0010       ;  <<#3
  -        ;   -      ;   1000    ;                      ; add 3
  -        ;  xxx1 ;   0000    ;   0010           ;  <<#4
  -        ;  xx10   ;   0000    ;   010             ;<<#5
 -        ;   x100   ;   0000    ;   10               ;<<#6
 -        ;   x1000   ;  0001    ;   0                ;<<#7
 -        ;   1011   ;               ;                      ; add 3
 1       ;    0110   ;   0010  ;                       ;<<#8
 1      ;     6         ;   2        ;
*/

uint8_t adjBCD(uint8_t r)
{
uint8_t tmp=r+0x03;
if(tmp&0x08) { r=tmp; }  // if (r+0x03)>7 (bit 3==1) r+=0x03
tmp=r+0x30;
if(tmp&0x80 ) {r =tmp ; } //bit7 , for packed if in the (r+0x03<<4 ) (bit 7==1) r+=0x03<<4 ;
return r;
}

uint8_t *  BinToBCD(uint16_t x  )
{

uint8_t count ;
uint8_t R[3];
R[0]=0;
R[1]=0;
//R[2]=0;
//clear Carry and use shift ing of x or load MSB of x to Carry without shifting, then use shifting after 

// Successive rotation
for (count=16 ; count>0 ; count--)  //total 16 steps
{
// add 3 for columns >=5
 /*
if(Th>=5) { Th+=3; }
if(H>=5) { H+=3; }
if(T>=5) { T+=3; }
if(O>=5) { O+=3; }
*/
 /*
Th=adjBCD(Th);
H=adjBCD(H);
T=adjBCD(T);
O=adjBCD(O);
*/
     //R[2]=adjBCD(R[2]);
     R[1]=adjBCD(R[1]);
     R[0]=adjBCD(R[0]);

  //R[2]= (R[2]<<1)|((R[1]>>7)&0x01);   //rlf r2
  R[1]= (R[1]<<1)|((R[0]>>7)&0x01);  // rlf r1,  R1= (H<<1)| ((R0>>3)&0x01);
  R[0]= (R[0]<<1)|((x>>count-1)&0x01); //  use carry for x shifting   into the
  //x=x<<1;  (shift left once  to load data into carry )
  /*
  Th=0x0F&(Th<<1)| ((H>>3)&0x01);   //Th=0x0F&((Th<<1)|(H.bit3)
  H=0x0F&(H<<1)| ((T>>3)&0x01);     //H=0x0F&((H<<1)|(T.bit3)
  T=0x0F&(T<<1)| ((O>>3)&0x01);     //T=0x0F&((T<<1)|(O.bit3)
  O=(uint8_t)0x0F&(O<<1)|((x>>15-i )&0x01);    //  MSB to O.bit0
   */
}

 return R ;
} 

 int main()
{
uint16_t x=220;
 for (x=0;x<=1023 ;x++)
{
 uint8_t* R=BinToBCD(x );  //packed, use masks
 printf ("\n x=%d ;   %d  %d % d %d   ",(int)x,(int)R[1]>>4, (int)R[1]&0x0f ,(int)R[0]>>4 ,(int)R[0] &0x0F  );
}

return 0 ;
}

For uint16_t (you can modify for uint32_t,uint8_t ) binary to (packed) BCD (for LEDs )  you can use modifyed  Microchip AN526 subroutines .  

https://sites.google.com/a/asu.e...

 

Last Edited: Wed. Nov 24, 2021 - 07:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not sure if there is code here for 32 bit, but I have code for 5 digits from 16 bit in less that 70 clk which I found good, but El Tangas have solved it in less that 50 clk. (the code is in a thread here somewhere)   Teatv

 

hello dear

Last Edited: Fri. Nov 26, 2021 - 08:05 AM

Pages