Example #1
0
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;
		}
	}
}
Example #2
0
void main(void) {
    ioinit();

    PWM_ON();

    while(1)
        sleep_mode();
}
Example #3
0
/*
 * 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;
}
Example #4
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;
		}
	}
}