Инициализация периферийного режима
Код
void usb_init(void)
{
uint16_t hw;
// Настраиваем пины (PORTD_Bit2 - прерывание от ISP, PORTD_Bit4 - ресет USB)
DDRD = DDRD & ~(1 << DDD2) | (1 << DDD4);
GICR_INT0 = 0;
MCUCR |= (1 << ISC01) | (1 << ISC00); // Работаем по фронту импульса прерывания
// Последовательность включения ISP
PORTD_Bit4 = 0;
__delay_cycles((unsigned long) (AVR_FREQUENCY * 1.1E-2));
PORTD_Bit4 = 1;
isp_read_register_16(ISP_REG_CHIP_ID, &hw); // Дамми чтение
__delay_cycles((unsigned long) (AVR_FREQUENCY * 1.1E-2));
// Инициализация интерфейса
hw = ISP_HMC_EDGE_TRIGGERED_INTERRUPT_MASK | ISP_HMC_COMMON_INT_MASK |
ISP_HMC_ACTIVE_HIGH_INTERRUPT_MASK;
isp_write_register_16(ISP_REG_HW_MODE_CONTROL, hw);
hw |= ISP_HMC_INTERFACE_LOCK_MASK;
isp_write_register_16(ISP_REG_HW_MODE_CONTROL, hw);
isp_write_register_16(ISP_REG_UNLOCK_DEVICE, ISP_UNLOCK_DEVICE_CODE);
isp_write_register_16(ISP_REG_MODE, ISP_MODE_SOFT_RESET_MASK);
isp_write_register_16(ISP_REG_MODE, 0);
// Основная инициализация
isp_write_register_16(ISP_REG_OTG_CONTROL_CLEAR, 0xFFFF);
isp_write_register_16(ISP_REG_OTG_CONTROL_SET, ISP_OTGC_HC2_DISABLE_MASK |
ISP_OTGC_SOFT_SELECT_HC_DC_MASK | ISP_OTGC_OTG_DISABLE_MASK);
isp_write_register_16(ISP_REG_TEST_MODE, ISP_TSTM_FORCE_FULL_SPEED_MASK);
isp_write_register_16(ISP_REG_DMA_ENDPOINT, USB_DEFAULT_INDEX);
isp_write_register_16(ISP_REG_INTERRUPT_CONFIGURATION,
ISP_INTC_ACTIVE_HIGH_INTERRUPT_MASK | ISP_INTC_PULSED_INTERRUPT_MASK);
isp_write_register_16(ISP_REG_INTERRUPT_PULSE_WIDTH, 0x0F); // 0.5 мкс
isp_write_register_32(ISP_REG_INTERRUPT_ENABLE, ISP_INTE_VBUS_MASK);
g_state = USB_STATE_NOT_ATTACHED;
// Включаем прерывания
GICR_INT0 = 1;
isp_write_register_16(ISP_REG_MODE, ISP_MODE_GLOBAL_INTERRUPT_ENABLE_MASK);
hw |= ISP_HMC_GLOBAL_INTERRUPT_ENABLE_MASK;
isp_write_register_16(ISP_REG_HW_MODE_CONTROL, hw);
}
// Функция для конфигурирования микросхемы в разных режимах.
// Режим USB_STATE_POWERED - после прерывания VBUS если VBUSSTAT == 1
// Режим USB_STATE_DEFAULT - после прерывания BUS RESET
// Режим USB_STATE_NOT_ATTACHED - после прерывания VBUS если VBUSSTAT == 0
static void configure(void)
{
uint16_t tmp;
switch (g_state)
{
case USB_STATE_NOT_ATTACHED:
isp_write_register_16(ISP_REG_MODE, ISP_MODE_GLOBAL_INTERRUPT_ENABLE_MASK);
isp_write_register_32(ISP_REG_INTERRUPT_ENABLE, ISP_INTE_VBUS_MASK);
isp_write_register_16(ISP_REG_ADDRESS, 0);
isp_write_register_16(ISP_REG_OTG_CONTROL_CLEAR, ISP_OTGC_DP_PULLUP_MASK);
break;
case USB_STATE_POWERED:
isp_write_register_16(ISP_REG_MODE, ISP_MODE_CLOCK_ALWAYS_ON_MASK |
ISP_MODE_GLOBAL_INTERRUPT_ENABLE_MASK);
isp_write_register_32(ISP_REG_INTERRUPT_ENABLE, ISP_INTE_VBUS_MASK |
ISP_INTE_BUS_RESET_MASK);
isp_write_register_16(ISP_REG_ADDRESS, ISP_ADDR_DEVICE_ENABLE_MASK);
isp_write_register_16(ISP_REG_OTG_CONTROL_SET, ISP_OTGC_DP_PULLUP_MASK);
break;
case USB_STATE_POWERED:
isp_write_register_16(ISP_REG_MODE,
ISP_MODE_GLOBAL_INTERRUPT_ENABLE_MASK | ISP_MODE_CLOCK_ALWAYS_ON_MASK);
isp_read_register_16(ISP_REG_INTERRUPT_CONFIGURATION, &tmp);
isp_write_register_16(ISP_REG_INTERRUPT_CONFIGURATION, tmp |
(1 << ISP_INTC_DATA_DEBUG_MODE_OUT_POS) |
(1 << ISP_INTC_DATA_DEBUG_MODE_IN_POS) |
(1 << ISP_INTC_CONTROL_0_DEBUG_MODE_POS));
isp_write_register_32(ISP_REG_INTERRUPT_ENABLE, ISP_INTE_VBUS_MASK |
ISP_INTE_BUS_RESET_MASK | ISP_INTE_SETUP_TOKEN_MASK |
ISP_INTE_ENDPOINT0_RECEIVE_MASK | ISP_INTE_ENDPOINT0_TRANSMIT_MASK);
break;
}
}