void main(void) { eeprom_read_block(&config, &stored_config.config, sizeof(config_t)); ioinit(); PWM_ON(); mode_id = 0; for(;;) { switch(state) { case STATE_MENU: // Show the menu menu(); break; case STATE_NORMAL: // Run a standard function modes[mode_id].run(); break; case STATE_SLEEPING: // Go to sleep enter_sleep(); state = STATE_SLEEPY; break; case STATE_SLEEPY: // Wait to enter STATE_SLEEPING or STATE_NORMAL break; case STATE_SLAVE: // Just refresh the display break; } } }
void main(void) { ioinit(); PWM_ON(); while(1) sleep_mode(); }
/* * Fv is derived from the variable frequency output. The variable frequency * output is configured using this formula: * * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword * * Fv = W x 2 ^ -16 x 27Mhz (reference clock) * * The period is: (period + 1) / Fv and "on" time is on / (period + 1) * * The PWM core framework specifies that the "duty_ns" parameter is in fact the * "on" time, so this translates directly into our HW programming here. */ static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct brcmstb_pwm *p = to_brcmstb_pwm(chip); unsigned long pc, dc, cword = CONST_VAR_F_MAX; unsigned int channel = pwm->hwpwm; u32 value; /* * If asking for a duty_ns equal to period_ns, we need to substract * the period value by 1 to make it shorter than the "on" time and * produce a flat 100% duty cycle signal, and max out the "on" time */ if (duty_ns == period_ns) { dc = PWM_ON_PERIOD_MAX; pc = PWM_ON_PERIOD_MAX - 1; goto done; } while (1) { u64 rate, tmp; /* * Calculate the base rate from base frequency and current * cword */ rate = (u64)clk_get_rate(p->clk) * (u64)cword; do_div(rate, 1 << CWORD_BIT_SIZE); tmp = period_ns * rate; do_div(tmp, NSEC_PER_SEC); pc = tmp; tmp = (duty_ns + 1) * rate; do_div(tmp, NSEC_PER_SEC); dc = tmp; /* * We can be called with separate duty and period updates, * so do not reject dc == 0 right away */ if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns)) return -EINVAL; /* We converged on a calculation */ if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX) break; /* * The cword needs to be a power of 2 for the variable * frequency generator to output a 50% duty cycle variable * frequency which is used as input clock to the fixed * frequency generator. */ cword >>= 1; /* * Desired periods are too large, we do not have a divider * for them */ if (cword < CONST_VAR_F_MIN) return -EINVAL; } done: /* * Configure the defined "cword" value to have the variable frequency * generator output a base frequency for the constant frequency * generator to derive from. */ spin_lock(&p->lock); brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel)); brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel)); /* Select constant frequency signal output */ value = brcmstb_pwm_readl(p, PWM_CTRL2); value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS); brcmstb_pwm_writel(p, value, PWM_CTRL2); /* Configure on and period value */ brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel)); brcmstb_pwm_writel(p, dc, PWM_ON(channel)); spin_unlock(&p->lock); return 0; }
inline static void handle_message(ir_message_t *message, uint8_t is_repeat) { if((message->command == COMMAND_STANDBY) && !is_repeat) { if(state & (STATE_SLEEPING | STATE_SLEEPY)) { state = STATE_NORMAL; PWM_ON(); } else { state = STATE_SLEEPING; // Disable the display TCCR0B &= ~(_BV(CS01) | _BV(CS00)); // Set the rows as inputs, with pullups disabled DDRD &= ~PORTD_ROWS; PORTD &= ~PORTD_ROWS; DDRA &= ~PORTA_ROWS; PORTA &= ~PORTA_ROWS; COLUMN_PORT = 0; } return; } if(state & (STATE_SLEEPING | STATE_SLEEPY)) return; if(message->field == 1) { // Handle regular commands switch(message->command) { case COMMAND_UP: keypresses |= KEY_UP; break; case COMMAND_DOWN: keypresses |= KEY_DOWN; break; case COMMAND_LEFT: keypresses |= KEY_LEFT; break; case COMMAND_RIGHT: keypresses |= KEY_RIGHT; break; case COMMAND_ENTER: keypresses |= KEY_ENTER; break; case COMMAND_PLAY_PAUSE: keypresses |= KEY_PLAY_PAUSE; break; case COMMAND_MENU: if(is_repeat) break; state = STATE_MENU; break; } } else { if(is_repeat) return; // Handle extended commands switch(message->command & EXT_COMMAND_MASK) { case EXT_COMMAND_DATA_ADDR: config_address = message->command & 0xFF; break; case EXT_COMMAND_DATA_WRITE: eeprom_update_byte(config_address + (uint8_t *)&stored_config, message->command & 0xFF); config_address++; break; case EXT_COMMAND_DISP_BEGIN_WRITE: // Swap buffer and display, and set buffer pointer to 0 buffer_address = 0; uint8_t *swap = display; display = buffer; buffer = swap; // Deliberate fallthrough case EXT_COMMAND_DISP_WRITE: buffer[buffer_address & 0x7] = message->command & 0xFF; buffer_address++; break; case EXT_COMMAND_SET_STATE: state = message->command & 0xFF; break; } } }