summaryrefslogtreecommitdiff
path: root/software_pwm_old.cb
blob: db609af8a4e704e9e519fa9a604c88e29e2c7552 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdint.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#include "software_pwm.h"
#include "pins.h"

static struct pwm_event {
  //ENTIRE port
  //(ex if pin 3, 2, 4 are on and we want 6, this should be 0b01011100)
  uint8_t port; 
  uint8_t time;
  struct pwm_event **map_ptr; 
} events[SOFTPWM_PIN_COUNT];

static struct pwm_event *pin_event_map[SOFTPWM_PIN_COUNT];


void init_softpwm() {
  SOFTPWM_DDR = 0xff; 
  for(size_t event_i = 0; event_i < SOFTPWM_PIN_COUNT; event_i++) {
    pin_event_map[event_i] = &events[event_i];
    events[event_i].map_ptr = &pin_event_map[event_i];
    events[event_i].time = event_i + 1;
    events[event_i].port = (1 << (event_i + 1)) - 1;
  }

  //use external 10mhz clock (we just have one laying around)
  //then prescale by 1024. Check at different freqs for brightness
  TCCR0A = 0b00000010;
  TIMSK0 = 0b00000011;
  OCR0A = events[0].time;
  TIFR0 = 0b00000010; //interupts enabled!
  sei();
}


static void event_move(struct pwm_event *dest, struct pwm_event *src) {
  *dest = *src;
  *(dest->map_ptr) = src;
}

/**
 * okay, let me explain. This is really weird and gross, I know. 
 * I did it when I was *very* low on sleep.
 * Why did I do it like this? Well, I was worried about accuracy; 
 * for some stupid reason I thought I really needed the actual pwm ISR to be as fast
 * as possible. I don't feel like redoing this in a simpler fasion, 
 * so while this code *is* embaracing, I'll get around to it later.
 **/
void softpwm_set(uint8_t pin, uint8_t value) { 
  struct pwm_event *event_to_shift;
  struct pwm_event modified_event_cpy = *pin_event_map[pin]; 

  modified_event_cpy.time = value;
  if(value < modified_event_cpy.time) {
    for(event_to_shift = pin_event_map[pin - 1];
        (event_to_shift >= events) 
        || (modified_event_cpy.time < event_to_shift[-1].time);
         event_to_shift = &event_to_shift[-1]) 
    {
      event_to_shift->port |= (1 << pin);
      event_move(&event_to_shift[1], event_to_shift);
    }
    event_move(&event_to_shift[1], &modified_event_cpy);
    return;
  }
  if(value > modified_event_cpy.time) {
    for(event_to_shift = pin_event_map[pin + 1];
        (event_to_shift < &events[SOFTPWM_PIN_COUNT]) 
        || (modified_event_cpy.time > event_to_shift[1].time);
         event_to_shift = &event_to_shift[1]) 
    {
      event_to_shift->port &= ~(1 << pin);
      event_move(&event_to_shift[-1], event_to_shift);
    }
  }
  event_move(&event_to_shift[-1], &modified_event_cpy);
}

ISR(TIMER0_OVF_vect) {
  SOFTPWM_PORT = 0;
  PORTA ^= 1;
}

//ISR for pwm timer. Need to look at assembly output to ensure proper optimization
//(would it be faster to have two different arrays vs a struct? idk if the offset is computed compile or runtime)
ISR(TIMER0_COMP_vect) {
  static uint8_t eventcount = 0;
  //eventcount = (eventcount <= SOFTPWM_PIN_COUNT) ? eventcount + 1 : 0;
  SOFTPWM_PORT = events[eventcount].port;
  eventcount = (eventcount + 1) % 8;
  OCR0A = events[eventcount].time;
  PORTA ^= 2;
}