#include "main.h" #include "cmsis_os.h" #include "ide.h" /* register addresses are in format CS0 CS1 A2 A1 A0 */ #define REG_DATA 0b01000 #define REG_ERROR_FEATURES 0b01001 #define REG_SECTOR_COUNT 0b01010 #define REG_SECTOR 0b01011 #define REG_CYL_LOW 0b01100 #define REG_CYL_HIGH 0b01101 #define REG_HEAD_DEVICE 0b01110 #define REG_STATUS_COMMAND 0b01111 #define BYTE_COUNT_LOW 0b10100 #define BYTE_COUNT_HIGH 0b10101 #define REG_CS0_MASK 0b00010000 #define REG_CS1_MASK 0b00001000 #define REG_DA2_MASK 0b00000100 #define REG_DA1_MASK 0b00000010 #define REG_DA0_MASK 0b00000001 static uint32_t ide_current_bus_mode = GPIO_MODE_INPUT; static inline void ide_set_bus_mode(uint32_t mode) { if (ide_current_bus_mode == mode) { return; // already in requested mode } ide_current_bus_mode = mode; GPIO_InitTypeDef GPIO_InitStruct = {0}; /*Configure GPIO pins : IDE_DD4_Pin IDE_DD5_Pin IDE_DD6_Pin IDE_DD7_Pin IDE_DD8_Pin IDE_DD9_Pin IDE_DD10_Pin IDE_DD11_Pin IDE_DD12_Pin IDE_DD13_Pin IDE_DD14_Pin IDE_DD15_Pin */ GPIO_InitStruct.Pin = IDE_DD4_Pin|IDE_DD5_Pin|IDE_DD6_Pin|IDE_DD7_Pin |IDE_DD8_Pin|IDE_DD9_Pin|IDE_DD10_Pin|IDE_DD11_Pin |IDE_DD12_Pin|IDE_DD13_Pin|IDE_DD14_Pin|IDE_DD15_Pin; GPIO_InitStruct.Mode = mode; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /*Configure GPIO pins : IDE_DD0_Pin IDE_DD1_Pin IDE_DD2_Pin IDE_DD3_Pin */ GPIO_InitStruct.Pin = IDE_DD0_Pin|IDE_DD1_Pin|IDE_DD2_Pin|IDE_DD3_Pin; GPIO_InitStruct.Mode = mode; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); } #define PORTD_BUS_IDR_MASK 0b00000000000000000000000000001111 #define PORTE_BUS_IDR_MASK 0b00000000000000001111111111110000 #define PORTD_BUS_BSRR_MASK 0b0000000000001111 #define PORTE_BUS_BSRR_MASK 0b1111111111110000 #define CORE_CLOCK_HZ 218E6 // 168 MHz #define CORE_CYCLE_TIME_S (1 / CORE_CLOCK_HZ) #define CORE_CYCLE_TIME_NS ((int)(CORE_CYCLE_TIME_S * 1E9 + 1)) // 6ns #define NDELAY_CYCLES_PER_ITERATION 3 static inline void ide_ndelay(unsigned int ns) { unsigned int iterations = (ns / CORE_CYCLE_TIME_NS) / NDELAY_CYCLES_PER_ITERATION + 1; asm volatile ( "0: subs %[i], 1;" "bne 0b;" : [i] "+r" (iterations) ); } static void ide_select_register(uint8_t reg) { HAL_GPIO_WritePin(IDE_CS0_GPIO_Port, IDE_CS0_Pin, reg & REG_CS0_MASK ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(IDE_CS1_GPIO_Port, IDE_CS1_Pin, reg & REG_CS1_MASK ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(IDE_DA0_GPIO_Port, IDE_DA0_Pin, reg & REG_DA0_MASK ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(IDE_DA1_GPIO_Port, IDE_DA1_Pin, reg & REG_DA1_MASK ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(IDE_DA2_GPIO_Port, IDE_DA2_Pin, reg & REG_DA2_MASK ? GPIO_PIN_SET : GPIO_PIN_RESET); } static uint16_t ide_register_read(uint8_t reg) { ide_set_bus_mode(GPIO_MODE_INPUT); ide_select_register(reg); ide_ndelay(70); HAL_GPIO_WritePin(IDE_DIOR_GPIO_Port, IDE_DIOR_Pin, GPIO_PIN_RESET); // flash read strobe (active low) ide_ndelay(290); uint16_t result = (uint16_t)((GPIOD->IDR & PORTD_BUS_IDR_MASK) | (GPIOE->IDR & PORTE_BUS_IDR_MASK)); HAL_GPIO_WritePin(IDE_DIOR_GPIO_Port, IDE_DIOR_Pin, GPIO_PIN_SET); // release read strobe return result; } static void ide_register_write(uint8_t reg, uint16_t word) { ide_set_bus_mode(GPIO_MODE_OUTPUT_PP); ide_select_register(reg); GPIOD->BSRR = ((~word & PORTD_BUS_BSRR_MASK) << 16) | (word & PORTD_BUS_BSRR_MASK); GPIOE->BSRR = ((~word & PORTE_BUS_BSRR_MASK) << 16) | (word & PORTE_BUS_BSRR_MASK); ide_ndelay(70); HAL_GPIO_WritePin(IDE_DIOW_GPIO_Port, IDE_DIOW_Pin, GPIO_PIN_RESET); // flash write strobe (active low) ide_ndelay(290); HAL_GPIO_WritePin(IDE_DIOW_GPIO_Port, IDE_DIOW_Pin, GPIO_PIN_SET); // release write strobe ide_ndelay(60); ide_set_bus_mode(GPIO_MODE_INPUT); } static void ide_error() { /*uint16_t error = ide_register_read_once(REG_ERROR_FEATURES); int amnf = error & 0b00000001; int tk0nf = error & 0b00000010; int abrt = error & 0b00000100; int mcr = error & 0b00001000; int idnf = error & 0b00010000; int mc = error & 0b00100000; int unc = error & 0b01000000;*/ HAL_GPIO_WritePin(IDE_RESET_GPIO_Port, IDE_RESET_Pin, GPIO_PIN_RESET); while(1) { HAL_GPIO_TogglePin(LED_2_GPIO_Port, LED_2_Pin); osDelay(100); } } int ide_ready() { uint16_t status = ide_register_read(REG_STATUS_COMMAND); if (status & 1) ide_error(); int ready = status & 0b0000000001000000; int busy = status & 0b0000000010000000; return ready && !busy; } static int ide_drq() { uint16_t status = ide_register_read(REG_STATUS_COMMAND); if (status & 1) ide_error(); return status & 0b0000000000001000; } static void ide_set_lba(uint32_t lba, uint16_t sector_count) { // 28 bit lba ide_register_write(REG_HEAD_DEVICE, (uint8_t)((lba & 0x0F000000) >> 24) | 0b11100000); // master device, LBA mode, lba most significant 4 bits ide_register_write(REG_CYL_HIGH, (uint8_t)((lba & 0x00FF0000) >> 16)); ide_register_write(REG_CYL_LOW, (uint8_t)((lba & 0x0000FF00) >> 8)); ide_register_write(REG_SECTOR, (uint8_t)((lba & 0x000000FF))); ide_register_write(REG_SECTOR_COUNT, sector_count); } static void ide_reset() { // never drive the bus unless when actually writing ide_set_bus_mode(GPIO_MODE_INPUT); // read/write strobes are active low -> normally keep them pulled high HAL_GPIO_WritePin(IDE_DIOR_GPIO_Port, IDE_DIOR_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(IDE_DIOW_GPIO_Port, IDE_DIOW_Pin, GPIO_PIN_SET); // now enable the level shifters, connecting the MCU and the IDE device HAL_GPIO_WritePin(TXS0108E_OE_GPIO_Port, TXS0108E_OE_Pin, GPIO_PIN_SET); // start device reset HAL_GPIO_WritePin(IDE_RESET_GPIO_Port, IDE_RESET_Pin, GPIO_PIN_RESET); // wait for the device to reset osDelay(1); HAL_GPIO_WritePin(IDE_RESET_GPIO_Port, IDE_RESET_Pin, GPIO_PIN_SET); osDelay(4); ide_register_write(REG_HEAD_DEVICE, 0b11100000); // select master device and LBA mode // set PIO default mode without IORDY ide_register_write(REG_SECTOR_COUNT, 0x01); // PIO default mode, disable IORDY (ACS-4 7.43.4) ide_register_write(REG_ERROR_FEATURES, 0x03); // "Set transfer mode" (ACS-4 7.43.2) ide_register_write(REG_STATUS_COMMAND, 0xEF); // SET FEATURES (ACS-4 7.43) while(!ide_ready()); } void ide_read_next_sector(uint8_t* buf) { uint16_t* buf16 = (uint16_t*) buf; while(!ide_drq()); ide_set_bus_mode(GPIO_MODE_INPUT); ide_select_register(REG_DATA); ide_ndelay(70); for (int i = 0; i < 256; i++) { HAL_GPIO_WritePin(IDE_DIOR_GPIO_Port, IDE_DIOR_Pin, GPIO_PIN_RESET); // flash read strobe (active low) ide_ndelay(165); buf16[i] = (uint16_t)((GPIOD->IDR & PORTD_BUS_IDR_MASK) | (GPIOE->IDR & PORTE_BUS_IDR_MASK)); HAL_GPIO_WritePin(IDE_DIOR_GPIO_Port, IDE_DIOR_Pin, GPIO_PIN_SET); // release read strobe } ide_ndelay(600); } static void ide_identify_device(uint8_t* buf) { while(!ide_ready()); ide_register_write(REG_STATUS_COMMAND, 0xEC); ide_read_next_sector(buf); } void ide_init() { ide_reset(); } int ide_get_num_sectors() { uint16_t buf[256]; ide_identify_device((uint8_t*) buf); return ((uint32_t)(buf[61]) << 16) | ((uint32_t)(buf[60])); } void ide_begin_read_sectors(uint32_t lba, uint16_t num_sectors) { while(!ide_ready()); ide_set_lba(lba, num_sectors); ide_register_write(REG_STATUS_COMMAND, 0x20); } void ide_write_next_sector(uint8_t* buf) { uint16_t* buf16 = (uint16_t*) buf; while(!ide_drq()); ide_set_bus_mode(GPIO_MODE_OUTPUT_PP); ide_select_register(REG_DATA); ide_ndelay(70); for (int i = 0; i < 256; i++) { uint16_t word = buf16[i]; GPIOD->BSRR = ((~word & PORTD_BUS_BSRR_MASK) << 16) | (word & PORTD_BUS_BSRR_MASK); GPIOE->BSRR = ((~word & PORTE_BUS_BSRR_MASK) << 16) | (word & PORTE_BUS_BSRR_MASK); ide_ndelay(60); HAL_GPIO_WritePin(IDE_DIOW_GPIO_Port, IDE_DIOW_Pin, GPIO_PIN_RESET); // flash write strobe (active low) ide_ndelay(165); HAL_GPIO_WritePin(IDE_DIOW_GPIO_Port, IDE_DIOW_Pin, GPIO_PIN_SET); // release write strobe } ide_ndelay(600); ide_set_bus_mode(GPIO_MODE_INPUT); } void ide_begin_write_sectors(uint32_t lba, uint16_t num_sectors) { while(!ide_ready()); ide_set_lba(lba, num_sectors); ide_register_write(REG_STATUS_COMMAND, 0x30); }