SD card v7 BSP (#361)
* Outdated apps: add api-light-usage * Gpio: update SD card CS pin settings * API-power: added fns to disable/enable external 3v3 dc-dc * API-gpio: separated SD card detect routines * Resources: removed sd cs pin * SD card: low level init now resets card power supply * App SD-filesystem: use new card detect fns * SD card: fix low level init headers * SD card: more realilable low level init, power reset, exit from command read cycle conditionally * App SD-filesystem: led notifiers, init cycling * SD card: backport to F4 * SD card: handle eject in init sequence * SD card: api to set level on detect gpio * SPI: api to set state on bus pins * SD card: set low state on bus pins while power reset Co-authored-by: coreglitch <mail@s3f.ru>
This commit is contained in:
		
							parent
							
								
									3f10ce47f0
								
							
						
					
					
						commit
						fef16a8e7a
					
				| @ -4,6 +4,7 @@ | |||||||
| #include "menu/menu.h" | #include "menu/menu.h" | ||||||
| #include "menu/menu_item.h" | #include "menu/menu_item.h" | ||||||
| #include "cli/cli.h" | #include "cli/cli.h" | ||||||
|  | #include "api-hal-sd.h" | ||||||
| 
 | 
 | ||||||
| FS_Api* fs_api_alloc() { | FS_Api* fs_api_alloc() { | ||||||
|     FS_Api* fs_api = furi_alloc(sizeof(FS_Api)); |     FS_Api* fs_api = furi_alloc(sizeof(FS_Api)); | ||||||
| @ -316,6 +317,95 @@ void app_sd_format_callback(void* context) { | |||||||
|     view_port_enabled_set(sd_app->view_port, false); |     view_port_enabled_set(sd_app->view_port, false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void app_sd_notify_wait_on() { | ||||||
|  |     api_hal_light_set(LightRed, 0xFF); | ||||||
|  |     api_hal_light_set(LightBlue, 0xFF); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void app_sd_notify_wait_off() { | ||||||
|  |     api_hal_light_set(LightRed, 0x00); | ||||||
|  |     api_hal_light_set(LightBlue, 0x00); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void app_sd_notify_success() { | ||||||
|  |     for(uint8_t i = 0; i < 3; i++) { | ||||||
|  |         delay(50); | ||||||
|  |         api_hal_light_set(LightGreen, 0xFF); | ||||||
|  |         delay(50); | ||||||
|  |         api_hal_light_set(LightGreen, 0x00); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void app_sd_notify_eject() { | ||||||
|  |     for(uint8_t i = 0; i < 3; i++) { | ||||||
|  |         delay(50); | ||||||
|  |         api_hal_light_set(LightBlue, 0xFF); | ||||||
|  |         delay(50); | ||||||
|  |         api_hal_light_set(LightBlue, 0x00); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void app_sd_notify_error() { | ||||||
|  |     for(uint8_t i = 0; i < 3; i++) { | ||||||
|  |         delay(50); | ||||||
|  |         api_hal_light_set(LightRed, 0xFF); | ||||||
|  |         delay(50); | ||||||
|  |         api_hal_light_set(LightRed, 0x00); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool app_sd_mount_card(SdApp* sd_app) { | ||||||
|  |     bool result = false; | ||||||
|  |     const uint8_t max_init_counts = 10; | ||||||
|  |     uint8_t counter = max_init_counts; | ||||||
|  |     uint8_t bsp_result; | ||||||
|  | 
 | ||||||
|  |     _fs_lock(&sd_app->info); | ||||||
|  | 
 | ||||||
|  |     while(result == false && counter > 0 && hal_sd_detect()) { | ||||||
|  |         app_sd_notify_wait_on(); | ||||||
|  | 
 | ||||||
|  |         if((counter % 10) == 0) { | ||||||
|  |             // power reset sd card
 | ||||||
|  |             bsp_result = BSP_SD_Init(true); | ||||||
|  |         } else { | ||||||
|  |             bsp_result = BSP_SD_Init(false); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(bsp_result) { | ||||||
|  |             // bsp error
 | ||||||
|  |             sd_app->info.status = SD_LOW_LEVEL_ERR; | ||||||
|  |         } else { | ||||||
|  |             sd_app->info.status = f_mount(&sd_app->info.fat_fs, sd_app->info.path, 1); | ||||||
|  | 
 | ||||||
|  |             if(sd_app->info.status == SD_OK || sd_app->info.status == SD_NO_FILESYSTEM) { | ||||||
|  |                 FATFS* fs; | ||||||
|  |                 uint32_t free_clusters; | ||||||
|  | 
 | ||||||
|  |                 sd_app->info.status = f_getfree(sd_app->info.path, &free_clusters, &fs); | ||||||
|  | 
 | ||||||
|  |                 if(sd_app->info.status == SD_OK || sd_app->info.status == SD_NO_FILESYSTEM) { | ||||||
|  |                     result = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         app_sd_notify_wait_off(); | ||||||
|  | 
 | ||||||
|  |         if(!result) { | ||||||
|  |             delay(1000); | ||||||
|  |             printf( | ||||||
|  |                 "[sd_filesystem] init(%d), error: %s\r\n", | ||||||
|  |                 counter, | ||||||
|  |                 fs_error_get_internal_desc(sd_app->info.status)); | ||||||
|  | 
 | ||||||
|  |             counter--; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     _fs_unlock(&sd_app->info); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void app_sd_unmount_card(SdApp* sd_app) { | void app_sd_unmount_card(SdApp* sd_app) { | ||||||
|     _fs_lock(&sd_app->info); |     _fs_lock(&sd_app->info); | ||||||
| 
 | 
 | ||||||
| @ -517,37 +607,44 @@ int32_t sd_filesystem(void* p) { | |||||||
|     // sd card cycle
 |     // sd card cycle
 | ||||||
|     bool sd_was_present = true; |     bool sd_was_present = true; | ||||||
| 
 | 
 | ||||||
|  |     // init detect pins
 | ||||||
|  |     hal_sd_detect_init(); | ||||||
|  | 
 | ||||||
|     while(true) { |     while(true) { | ||||||
|         if(sd_was_present) { |         if(sd_was_present) { | ||||||
|             if(hal_gpio_read_sd_detect()) { |             if(hal_sd_detect()) { | ||||||
|                 printf("[sd_filesystem] card detected\r\n"); |                 printf("[sd_filesystem] card detected\r\n"); | ||||||
|  |                 app_sd_mount_card(sd_app); | ||||||
| 
 | 
 | ||||||
|                 uint8_t bsp_result = BSP_SD_Init(); |                 if(sd_app->info.status != SD_OK) { | ||||||
| 
 |                     printf( | ||||||
|                 if(bsp_result) { |                         "[sd_filesystem] sd init error: %s\r\n", | ||||||
|                     sd_app->info.status = SD_LOW_LEVEL_ERR; |                         fs_error_get_internal_desc(sd_app->info.status)); | ||||||
|                     printf("[sd_filesystem] bsp error: %x\n", bsp_result); |                     app_sd_notify_error(); | ||||||
|                 } else { |                 } else { | ||||||
|                     printf("[sd_filesystem] bsp ok\r\n"); |                     printf("[sd_filesystem] sd init ok\r\n"); | ||||||
|                     sd_app->info.status = f_mount(&sd_app->info.fat_fs, sd_app->info.path, 1); |                     app_sd_notify_success(); | ||||||
| 
 |  | ||||||
|                     if(sd_app->info.status != SD_OK) { |  | ||||||
|                         printf("[sd_filesystem] mount error: %d\n", sd_app->info.status); |  | ||||||
|                     } else { |  | ||||||
|                         printf("[sd_filesystem] mount ok\r\n"); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 view_port_enabled_set(sd_app->icon.view_port, true); |                 view_port_enabled_set(sd_app->icon.view_port, true); | ||||||
|                 sd_was_present = false; |                 sd_was_present = false; | ||||||
|  | 
 | ||||||
|  |                 if(!hal_sd_detect()) { | ||||||
|  |                     printf("[sd_filesystem] card removed\r\n"); | ||||||
|  | 
 | ||||||
|  |                     view_port_enabled_set(sd_app->icon.view_port, false); | ||||||
|  |                     app_sd_unmount_card(sd_app); | ||||||
|  |                     sd_was_present = true; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             if(!hal_gpio_read_sd_detect()) { |             if(!hal_sd_detect()) { | ||||||
|                 printf("[sd_filesystem] card removed\r\n"); |                 printf("[sd_filesystem] card removed\r\n"); | ||||||
| 
 | 
 | ||||||
|                 view_port_enabled_set(sd_app->icon.view_port, false); |                 view_port_enabled_set(sd_app->icon.view_port, false); | ||||||
|                 app_sd_unmount_card(sd_app); |                 app_sd_unmount_card(sd_app); | ||||||
|                 sd_was_present = true; |                 sd_was_present = true; | ||||||
|  |                 app_sd_notify_eject(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -83,6 +83,16 @@ float api_hal_power_get_usb_voltage(); | |||||||
| /* Get power system component state */ | /* Get power system component state */ | ||||||
| void api_hal_power_dump_state(string_t buffer); | void api_hal_power_dump_state(string_t buffer); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Enable 3.3v on external gpio and sd card | ||||||
|  |  */ | ||||||
|  | void api_hal_power_enable_external_3_3v(); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Disable 3.3v on external gpio and sd card | ||||||
|  |  */ | ||||||
|  | void api_hal_power_disable_external_3_3v(); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
							
								
								
									
										30
									
								
								firmware/targets/api-hal-include/api-hal-sd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								firmware/targets/api-hal-include/api-hal-sd.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Init SD card detect | ||||||
|  |  *  | ||||||
|  |  */ | ||||||
|  | void hal_sd_detect_init(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Set SD card detect pin to low | ||||||
|  |  *  | ||||||
|  |  */ | ||||||
|  | void hal_sd_detect_set_low(void); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Get SD card status | ||||||
|  |  *  | ||||||
|  |  * @return true if SD card present | ||||||
|  |  * @return false if SD card not present | ||||||
|  |  */ | ||||||
|  | bool hal_sd_detect(void); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @ -92,7 +92,9 @@ | |||||||
| #include "string.h" | #include "string.h" | ||||||
| #include "stdio.h" | #include "stdio.h" | ||||||
| #include "spi.h" | #include "spi.h" | ||||||
| #include "api-hal-spi.h" | #include <api-hal-spi.h> | ||||||
|  | #include <api-hal-power.h> | ||||||
|  | #include <api-hal-delay.h> | ||||||
| 
 | 
 | ||||||
| /** @addtogroup BSP
 | /** @addtogroup BSP
 | ||||||
|   * @{ |   * @{ | ||||||
| @ -290,19 +292,33 @@ static uint8_t SD_ReadData(void); | |||||||
|   *         - MSD_ERROR: Sequence failed |   *         - MSD_ERROR: Sequence failed | ||||||
|   *         - MSD_OK: Sequence succeed |   *         - MSD_OK: Sequence succeed | ||||||
|   */ |   */ | ||||||
| uint8_t BSP_SD_Init(void) { | uint8_t BSP_SD_Init(bool reset_card) { | ||||||
|     /* Init to maximum slow speed */ |     /* Slow speed init */ | ||||||
|     // TODO: SPI manager
 | 
 | ||||||
|  |     /* TODO: SPI manager */ | ||||||
|     api_hal_spi_lock_device(&sd_slow_spi); |     api_hal_spi_lock_device(&sd_slow_spi); | ||||||
| 
 | 
 | ||||||
|  |     /* We must reset card in spi_lock context */ | ||||||
|  |     if(reset_card) { | ||||||
|  |         api_hal_power_disable_external_3_3v(); | ||||||
|  |         delay(100); | ||||||
|  |         api_hal_power_enable_external_3_3v(); | ||||||
|  |         delay(100); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /* Configure IO functionalities for SD pin */ |     /* Configure IO functionalities for SD pin */ | ||||||
|     SD_IO_Init(); |     SD_IO_Init(); | ||||||
| 
 | 
 | ||||||
|     /* SD detection pin is not physically mapped on the Adafruit shield */ |     /* SD detection pin is not physically mapped on the Adafruit shield */ | ||||||
|     SdStatus = SD_PRESENT; |     SdStatus = SD_PRESENT; | ||||||
|     uint8_t res = SD_GoIdleState(); |     uint8_t res = BSP_SD_ERROR; | ||||||
| 
 | 
 | ||||||
|     // TODO: SPI manager
 |     for(uint8_t i = 0; i < 128; i++) { | ||||||
|  |         res = SD_GoIdleState(); | ||||||
|  |         if(res == BSP_SD_OK) break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* TODO: SPI manager */ | ||||||
|     api_hal_spi_unlock_device(&sd_slow_spi); |     api_hal_spi_unlock_device(&sd_slow_spi); | ||||||
| 
 | 
 | ||||||
|     /* SD initialized and set to SPI mode properly */ |     /* SD initialized and set to SPI mode properly */ | ||||||
| @ -872,9 +888,10 @@ uint8_t SD_GetDataResponse(void) { | |||||||
|   */ |   */ | ||||||
| uint8_t SD_GoIdleState(void) { | uint8_t SD_GoIdleState(void) { | ||||||
|     SD_CmdAnswer_typedef response; |     SD_CmdAnswer_typedef response; | ||||||
|     __IO uint8_t counter = 0; |     __IO uint8_t counter; | ||||||
|     /* Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode and 
 |     /* Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode and 
 | ||||||
|      wait for In Idle State Response (R1 Format) equal to 0x01 */ |      wait for In Idle State Response (R1 Format) equal to 0x01 */ | ||||||
|  |     counter = 0; | ||||||
|     do { |     do { | ||||||
|         counter++; |         counter++; | ||||||
|         response = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95, SD_ANSWER_R1_EXPECTED); |         response = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95, SD_ANSWER_R1_EXPECTED); | ||||||
| @ -892,7 +909,9 @@ uint8_t SD_GoIdleState(void) { | |||||||
|     SD_IO_WriteByte(SD_DUMMY_BYTE); |     SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|     if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { |     if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { | ||||||
|         /* initialise card V1 */ |         /* initialise card V1 */ | ||||||
|  |         counter = 0; | ||||||
|         do { |         do { | ||||||
|  |             counter++; | ||||||
|             /* initialise card V1 */ |             /* initialise card V1 */ | ||||||
|             /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ |             /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ | ||||||
|             response = SD_SendCmd(SD_CMD_APP_CMD, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); |             response = SD_SendCmd(SD_CMD_APP_CMD, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
| @ -903,11 +922,16 @@ uint8_t SD_GoIdleState(void) { | |||||||
|             response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); |             response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|             SD_IO_CSState(1); |             SD_IO_CSState(1); | ||||||
|             SD_IO_WriteByte(SD_DUMMY_BYTE); |             SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|  |             if(counter >= SD_MAX_TRY) { | ||||||
|  |                 return BSP_SD_ERROR; | ||||||
|  |             } | ||||||
|         } while(response.r1 == SD_R1_IN_IDLE_STATE); |         } while(response.r1 == SD_R1_IN_IDLE_STATE); | ||||||
|         flag_SDHC = 0; |         flag_SDHC = 0; | ||||||
|     } else if(response.r1 == SD_R1_IN_IDLE_STATE) { |     } else if(response.r1 == SD_R1_IN_IDLE_STATE) { | ||||||
|         /* initialise card V2 */ |         /* initialise card V2 */ | ||||||
|  |         counter = 0; | ||||||
|         do { |         do { | ||||||
|  |             counter++; | ||||||
|             /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ |             /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ | ||||||
|             response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); |             response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|             SD_IO_CSState(1); |             SD_IO_CSState(1); | ||||||
| @ -917,10 +941,15 @@ uint8_t SD_GoIdleState(void) { | |||||||
|             response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x40000000, 0xFF, SD_ANSWER_R1_EXPECTED); |             response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x40000000, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|             SD_IO_CSState(1); |             SD_IO_CSState(1); | ||||||
|             SD_IO_WriteByte(SD_DUMMY_BYTE); |             SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|  |             if(counter >= SD_MAX_TRY) { | ||||||
|  |                 return BSP_SD_ERROR; | ||||||
|  |             } | ||||||
|         } while(response.r1 == SD_R1_IN_IDLE_STATE); |         } while(response.r1 == SD_R1_IN_IDLE_STATE); | ||||||
| 
 | 
 | ||||||
|         if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { |         if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { | ||||||
|  |             counter = 0; | ||||||
|             do { |             do { | ||||||
|  |                 counter++; | ||||||
|                 /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ |                 /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ | ||||||
|                 response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); |                 response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|                 SD_IO_CSState(1); |                 SD_IO_CSState(1); | ||||||
| @ -933,6 +962,9 @@ uint8_t SD_GoIdleState(void) { | |||||||
|                     SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); |                     SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|                 SD_IO_CSState(1); |                 SD_IO_CSState(1); | ||||||
|                 SD_IO_WriteByte(SD_DUMMY_BYTE); |                 SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|  |                 if(counter >= SD_MAX_TRY) { | ||||||
|  |                     return BSP_SD_ERROR; | ||||||
|  |                 } | ||||||
|             } while(response.r1 == SD_R1_IN_IDLE_STATE); |             } while(response.r1 == SD_R1_IN_IDLE_STATE); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -34,193 +34,185 @@ | |||||||
|   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|   * |   * | ||||||
|   ****************************************************************************** |   ****************************************************************************** | ||||||
|   */  |   */ | ||||||
| 
 | 
 | ||||||
| /* Define to prevent recursive inclusion -------------------------------------*/ | /* Define to prevent recursive inclusion -------------------------------------*/ | ||||||
| #ifndef __STM32_ADAFRUIT_SD_H | #ifndef __STM32_ADAFRUIT_SD_H | ||||||
| #define __STM32_ADAFRUIT_SD_H | #define __STM32_ADAFRUIT_SD_H | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  extern "C" { | extern "C" { | ||||||
| #endif  | #endif | ||||||
| 
 | 
 | ||||||
| /* Includes ------------------------------------------------------------------*/ | /* Includes ------------------------------------------------------------------*/ | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| /** @addtogroup BSP
 | /** @addtogroup BSP
 | ||||||
|   * @{ |   * @{ | ||||||
|   */  |   */ | ||||||
| #define __IO    volatile    | #define __IO volatile | ||||||
|     | 
 | ||||||
| /** @addtogroup STM32_ADAFRUIT
 | /** @addtogroup STM32_ADAFRUIT
 | ||||||
|   * @{ |   * @{ | ||||||
|   */ |   */ | ||||||
|      | 
 | ||||||
| /** @defgroup STM32_ADAFRUIT_SD
 | /** @defgroup STM32_ADAFRUIT_SD
 | ||||||
|   * @{ |   * @{ | ||||||
|   */     |   */ | ||||||
| 
 | 
 | ||||||
| /** @defgroup STM32_ADAFRUIT_SD_Exported_Types
 | /** @defgroup STM32_ADAFRUIT_SD_Exported_Types
 | ||||||
|   * @{ |   * @{ | ||||||
|   */ |   */ | ||||||
|     | 
 | ||||||
| /** 
 | /** 
 | ||||||
|   * @brief  SD status structure definition   |   * @brief  SD status structure definition   | ||||||
|   */      |   */ | ||||||
| enum {     | enum { BSP_SD_OK = 0x00, MSD_OK = 0x00, BSP_SD_ERROR = 0x01, BSP_SD_TIMEOUT }; | ||||||
|       BSP_SD_OK = 0x00,       | 
 | ||||||
|       MSD_OK = 0x00, | typedef struct { | ||||||
|       BSP_SD_ERROR = 0x01, |     uint8_t Reserved1 : 2; /* Reserved */ | ||||||
|       BSP_SD_TIMEOUT |     uint16_t DeviceSize : 12; /* Device Size */ | ||||||
| }; |     uint8_t MaxRdCurrentVDDMin : 3; /* Max. read current @ VDD min */ | ||||||
|     |     uint8_t MaxRdCurrentVDDMax : 3; /* Max. read current @ VDD max */ | ||||||
| typedef struct               |     uint8_t MaxWrCurrentVDDMin : 3; /* Max. write current @ VDD min */ | ||||||
| { |     uint8_t MaxWrCurrentVDDMax : 3; /* Max. write current @ VDD max */ | ||||||
|   uint8_t  Reserved1:2;               /* Reserved */ |     uint8_t DeviceSizeMul : 3; /* Device size multiplier */ | ||||||
|   uint16_t DeviceSize:12;             /* Device Size */ |  | ||||||
|   uint8_t  MaxRdCurrentVDDMin:3;      /* Max. read current @ VDD min */ |  | ||||||
|   uint8_t  MaxRdCurrentVDDMax:3;      /* Max. read current @ VDD max */ |  | ||||||
|   uint8_t  MaxWrCurrentVDDMin:3;      /* Max. write current @ VDD min */ |  | ||||||
|   uint8_t  MaxWrCurrentVDDMax:3;      /* Max. write current @ VDD max */ |  | ||||||
|   uint8_t  DeviceSizeMul:3;           /* Device size multiplier */ |  | ||||||
| } struct_v1; | } struct_v1; | ||||||
| 
 | 
 | ||||||
| 
 | typedef struct { | ||||||
| typedef struct               |     uint8_t Reserved1 : 6; /* Reserved */ | ||||||
| { |     uint32_t DeviceSize : 22; /* Device Size */ | ||||||
|   uint8_t  Reserved1:6;               /* Reserved */ |     uint8_t Reserved2 : 1; /* Reserved */ | ||||||
|   uint32_t DeviceSize:22;             /* Device Size */ |  | ||||||
|   uint8_t  Reserved2:1;               /* Reserved */ |  | ||||||
| } struct_v2; | } struct_v2; | ||||||
| 
 | 
 | ||||||
| /** 
 | /** 
 | ||||||
|   * @brief  Card Specific Data: CSD Register |   * @brief  Card Specific Data: CSD Register | ||||||
|   */  |   */ | ||||||
| typedef struct | typedef struct { | ||||||
| { |     /* Header part */ | ||||||
|   /* Header part */ |     uint8_t CSDStruct : 2; /* CSD structure */ | ||||||
|   uint8_t  CSDStruct:2;            /* CSD structure */ |     uint8_t Reserved1 : 6; /* Reserved */ | ||||||
|   uint8_t  Reserved1:6;            /* Reserved */ |     uint8_t TAAC : 8; /* Data read access-time 1 */ | ||||||
|   uint8_t  TAAC:8;                 /* Data read access-time 1 */ |     uint8_t NSAC : 8; /* Data read access-time 2 in CLK cycles */ | ||||||
|   uint8_t  NSAC:8;                 /* Data read access-time 2 in CLK cycles */ |     uint8_t MaxBusClkFrec : 8; /* Max. bus clock frequency */ | ||||||
|   uint8_t  MaxBusClkFrec:8;        /* Max. bus clock frequency */ |     uint16_t CardComdClasses : 12; /* Card command classes */ | ||||||
|   uint16_t CardComdClasses:12;      /* Card command classes */ |     uint8_t RdBlockLen : 4; /* Max. read data block length */ | ||||||
|   uint8_t  RdBlockLen:4;           /* Max. read data block length */ |     uint8_t PartBlockRead : 1; /* Partial blocks for read allowed */ | ||||||
|   uint8_t  PartBlockRead:1;        /* Partial blocks for read allowed */ |     uint8_t WrBlockMisalign : 1; /* Write block misalignment */ | ||||||
|   uint8_t  WrBlockMisalign:1;      /* Write block misalignment */ |     uint8_t RdBlockMisalign : 1; /* Read block misalignment */ | ||||||
|   uint8_t  RdBlockMisalign:1;      /* Read block misalignment */ |     uint8_t DSRImpl : 1; /* DSR implemented */ | ||||||
|   uint8_t  DSRImpl:1;              /* DSR implemented */ | 
 | ||||||
|    |     /* v1 or v2 struct */ | ||||||
|   /* v1 or v2 struct */ |     union csd_version { | ||||||
|   union csd_version { |         struct_v1 v1; | ||||||
|     struct_v1 v1; |         struct_v2 v2; | ||||||
|     struct_v2 v2; |     } version; | ||||||
|   } version; | 
 | ||||||
|    |     uint8_t EraseSingleBlockEnable : 1; /* Erase single block enable */ | ||||||
|   uint8_t  EraseSingleBlockEnable:1;  /* Erase single block enable */ |     uint8_t EraseSectorSize : 7; /* Erase group size multiplier */ | ||||||
|   uint8_t  EraseSectorSize:7;         /* Erase group size multiplier */ |     uint8_t WrProtectGrSize : 7; /* Write protect group size */ | ||||||
|   uint8_t  WrProtectGrSize:7;         /* Write protect group size */ |     uint8_t WrProtectGrEnable : 1; /* Write protect group enable */ | ||||||
|   uint8_t  WrProtectGrEnable:1;       /* Write protect group enable */ |     uint8_t Reserved2 : 2; /* Reserved */ | ||||||
|   uint8_t  Reserved2:2;               /* Reserved */ |     uint8_t WrSpeedFact : 3; /* Write speed factor */ | ||||||
|   uint8_t  WrSpeedFact:3;             /* Write speed factor */ |     uint8_t MaxWrBlockLen : 4; /* Max. write data block length */ | ||||||
|   uint8_t  MaxWrBlockLen:4;           /* Max. write data block length */ |     uint8_t WriteBlockPartial : 1; /* Partial blocks for write allowed */ | ||||||
|   uint8_t  WriteBlockPartial:1;       /* Partial blocks for write allowed */ |     uint8_t Reserved3 : 5; /* Reserved */ | ||||||
|   uint8_t  Reserved3:5;               /* Reserved */ |     uint8_t FileFormatGrouop : 1; /* File format group */ | ||||||
|   uint8_t  FileFormatGrouop:1;        /* File format group */ |     uint8_t CopyFlag : 1; /* Copy flag (OTP) */ | ||||||
|   uint8_t  CopyFlag:1;                /* Copy flag (OTP) */ |     uint8_t PermWrProtect : 1; /* Permanent write protection */ | ||||||
|   uint8_t  PermWrProtect:1;           /* Permanent write protection */ |     uint8_t TempWrProtect : 1; /* Temporary write protection */ | ||||||
|   uint8_t  TempWrProtect:1;           /* Temporary write protection */ |     uint8_t FileFormat : 2; /* File Format */ | ||||||
|   uint8_t  FileFormat:2;              /* File Format */ |     uint8_t Reserved4 : 2; /* Reserved */ | ||||||
|   uint8_t  Reserved4:2;               /* Reserved */ |     uint8_t crc : 7; /* Reserved */ | ||||||
|   uint8_t  crc:7;                     /* Reserved */ |     uint8_t Reserved5 : 1; /* always 1*/ | ||||||
|   uint8_t  Reserved5:1;               /* always 1*/ | 
 | ||||||
|    |  | ||||||
| } SD_CSD; | } SD_CSD; | ||||||
| 
 | 
 | ||||||
| /** 
 | /** 
 | ||||||
|   * @brief  Card Identification Data: CID Register    |   * @brief  Card Identification Data: CID Register    | ||||||
|   */ |   */ | ||||||
| typedef struct | typedef struct { | ||||||
| { |     __IO uint8_t ManufacturerID; /* ManufacturerID */ | ||||||
|   __IO uint8_t  ManufacturerID;       /* ManufacturerID */ |     __IO uint16_t OEM_AppliID; /* OEM/Application ID */ | ||||||
|   __IO uint16_t OEM_AppliID;          /* OEM/Application ID */ |     __IO uint32_t ProdName1; /* Product Name part1 */ | ||||||
|   __IO uint32_t ProdName1;            /* Product Name part1 */ |     __IO uint8_t ProdName2; /* Product Name part2*/ | ||||||
|   __IO uint8_t  ProdName2;            /* Product Name part2*/ |     __IO uint8_t ProdRev; /* Product Revision */ | ||||||
|   __IO uint8_t  ProdRev;              /* Product Revision */ |     __IO uint32_t ProdSN; /* Product Serial Number */ | ||||||
|   __IO uint32_t ProdSN;               /* Product Serial Number */ |     __IO uint8_t Reserved1; /* Reserved1 */ | ||||||
|   __IO uint8_t  Reserved1;            /* Reserved1 */ |     __IO uint16_t ManufactDate; /* Manufacturing Date */ | ||||||
|   __IO uint16_t ManufactDate;         /* Manufacturing Date */ |     __IO uint8_t CID_CRC; /* CID CRC */ | ||||||
|   __IO uint8_t  CID_CRC;              /* CID CRC */ |     __IO uint8_t Reserved2; /* always 1 */ | ||||||
|   __IO uint8_t  Reserved2;            /* always 1 */ |  | ||||||
| } SD_CID; | } SD_CID; | ||||||
| 
 | 
 | ||||||
| /** 
 | /** 
 | ||||||
|   * @brief SD Card information  |   * @brief SD Card information  | ||||||
|   */ |   */ | ||||||
| typedef struct | typedef struct { | ||||||
| { |     SD_CSD Csd; | ||||||
|   SD_CSD Csd; |     SD_CID Cid; | ||||||
|   SD_CID Cid; |     uint64_t CardCapacity; /*!< Card Capacity */ | ||||||
|   uint64_t CardCapacity;              /*!< Card Capacity */ |     uint32_t CardBlockSize; /*!< Card Block Size */ | ||||||
|   uint32_t CardBlockSize;             /*!< Card Block Size */ |     uint32_t LogBlockNbr; /*!< Specifies the Card logical Capacity in blocks   */ | ||||||
|   uint32_t LogBlockNbr;               /*!< Specifies the Card logical Capacity in blocks   */ |     uint32_t LogBlockSize; /*!< Specifies logical block size in bytes           */ | ||||||
|   uint32_t LogBlockSize;              /*!< Specifies logical block size in bytes           */ |  | ||||||
| } SD_CardInfo; | } SD_CardInfo; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @} |   * @} | ||||||
|   */ |   */ | ||||||
|    | 
 | ||||||
| /** @defgroup STM32_ADAFRUIT_SPI_SD_Exported_Constants
 | /** @defgroup STM32_ADAFRUIT_SPI_SD_Exported_Constants
 | ||||||
|   * @{ |   * @{ | ||||||
|   */  |   */ | ||||||
|    | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @brief  Block Size |   * @brief  Block Size | ||||||
|   */ |   */ | ||||||
| #define SD_BLOCK_SIZE    0x200 | #define SD_BLOCK_SIZE 0x200 | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @brief  SD detection on its memory slot |   * @brief  SD detection on its memory slot | ||||||
|   */ |   */ | ||||||
| #define SD_PRESENT               ((uint8_t)0x01) | #define SD_PRESENT ((uint8_t)0x01) | ||||||
| #define SD_NOT_PRESENT           ((uint8_t)0x00) | #define SD_NOT_PRESENT ((uint8_t)0x00) | ||||||
| 
 | 
 | ||||||
| #define SD_DATATIMEOUT           ((uint32_t)100000000) | #define SD_DATATIMEOUT ((uint32_t)100000000) | ||||||
| 
 | 
 | ||||||
| /** 
 | /** 
 | ||||||
|   * @brief SD Card information structure  |   * @brief SD Card information structure  | ||||||
|   */    |   */ | ||||||
| #define BSP_SD_CardInfo SD_CardInfo | #define BSP_SD_CardInfo SD_CardInfo | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @} |   * @} | ||||||
|   */ |   */ | ||||||
|    | 
 | ||||||
| /** @defgroup STM32_ADAFRUIT_SD_Exported_Macro
 | /** @defgroup STM32_ADAFRUIT_SD_Exported_Macro
 | ||||||
|   * @{ |   * @{ | ||||||
|   */  |   */ | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @} |   * @} | ||||||
|   */  |   */ | ||||||
| 
 | 
 | ||||||
| /** @defgroup STM32_ADAFRUIT_SD_Exported_Functions
 | /** @defgroup STM32_ADAFRUIT_SD_Exported_Functions
 | ||||||
|   * @{ |   * @{ | ||||||
|   */    |   */ | ||||||
| uint8_t BSP_SD_Init(void); | uint8_t BSP_SD_Init(bool reset_card); | ||||||
| uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); | uint8_t | ||||||
| uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); | BSP_SD_ReadBlocks(uint32_t* pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); | ||||||
|  | uint8_t | ||||||
|  | BSP_SD_WriteBlocks(uint32_t* pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); | ||||||
| uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); | uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); | ||||||
| uint8_t BSP_SD_GetCardState(void); | uint8_t BSP_SD_GetCardState(void); | ||||||
| uint8_t BSP_SD_GetCardInfo(SD_CardInfo *pCardInfo); | uint8_t BSP_SD_GetCardInfo(SD_CardInfo* pCardInfo); | ||||||
|     | 
 | ||||||
| /* Link functions for SD Card peripheral*/ | /* Link functions for SD Card peripheral*/ | ||||||
| void    SD_SPI_Slow_Init(void); | void SD_SPI_Slow_Init(void); | ||||||
| void    SD_SPI_Fast_Init(void); | void SD_SPI_Fast_Init(void); | ||||||
| void    SD_IO_Init(void); | void SD_IO_Init(void); | ||||||
| void    SD_IO_CSState(uint8_t state); | void SD_IO_CSState(uint8_t state); | ||||||
| void    SD_IO_WriteReadData(const uint8_t *DataIn, uint8_t *DataOut, uint16_t DataLength); | void SD_IO_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength); | ||||||
| uint8_t SD_IO_WriteByte(uint8_t Data); | uint8_t SD_IO_WriteByte(uint8_t Data); | ||||||
| 
 | 
 | ||||||
| /* Link function for HAL delay */ | /* Link function for HAL delay */ | ||||||
| @ -234,18 +226,18 @@ void HAL_Delay(__IO uint32_t Delay); | |||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @} |   * @} | ||||||
|   */  |   */ | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @} |   * @} | ||||||
|   */  |   */ | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @} |   * @} | ||||||
|   */  |   */ | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|   * @} |   * @} | ||||||
|   */  |   */ | ||||||
| 
 | 
 | ||||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||||
|  | |||||||
| @ -1,7 +1,4 @@ | |||||||
| #include <api-hal-gpio.h> | #include <api-hal-gpio.h> | ||||||
| #include <api-hal-spi.h> |  | ||||||
| #include <api-hal-resources.h> |  | ||||||
| #include <api-hal-delay.h> |  | ||||||
| 
 | 
 | ||||||
| // init GPIO
 | // init GPIO
 | ||||||
| void hal_gpio_init( | void hal_gpio_init( | ||||||
| @ -20,33 +17,6 @@ void hal_gpio_init( | |||||||
|     HAL_GPIO_Init(gpio->port, &GPIO_InitStruct); |     HAL_GPIO_Init(gpio->port, &GPIO_InitStruct); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool hal_gpio_read_sd_detect(void) { |  | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     // TODO open record
 |  | ||||||
|     const GpioPin* sd_cs_record = &sd_cs_gpio; |  | ||||||
| 
 |  | ||||||
|     // TODO: SPI manager
 |  | ||||||
|     api_hal_spi_lock(sd_fast_spi.spi); |  | ||||||
| 
 |  | ||||||
|     // configure pin as input
 |  | ||||||
|     gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); |  | ||||||
|     delay(1); |  | ||||||
| 
 |  | ||||||
|     // if gpio_read == 0 return true else return false
 |  | ||||||
|     result = !gpio_read(sd_cs_record); |  | ||||||
| 
 |  | ||||||
|     // configure pin back
 |  | ||||||
|     gpio_init_ex(sd_cs_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); |  | ||||||
|     gpio_write(sd_cs_record, 1); |  | ||||||
|     delay(1); |  | ||||||
| 
 |  | ||||||
|     // TODO: SPI manager
 |  | ||||||
|     api_hal_spi_unlock(sd_fast_spi.spi); |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void enable_cc1101_irq() { | void enable_cc1101_irq() { | ||||||
|     HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0); |     HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0); | ||||||
|     HAL_NVIC_EnableIRQ(EXTI4_IRQn); |     HAL_NVIC_EnableIRQ(EXTI4_IRQn); | ||||||
|  | |||||||
| @ -68,8 +68,6 @@ static inline bool hal_gpio_read(const GpioPin* gpio) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool hal_gpio_read_sd_detect(void); |  | ||||||
| 
 |  | ||||||
| void enable_cc1101_irq(); | void enable_cc1101_irq(); | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  | |||||||
| @ -195,3 +195,11 @@ void api_hal_power_dump_state(string_t buffer) { | |||||||
|         bq25896_get_ntc_mpct() |         bq25896_get_ntc_mpct() | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void api_hal_power_enable_external_3_3v(){ | ||||||
|  |     // nothing to do
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_power_disable_external_3_3v(){ | ||||||
|  |     // nothing to do
 | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								firmware/targets/f4/api-hal/api-hal-sd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								firmware/targets/f4/api-hal/api-hal-sd.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | #include <api-hal-sd.h> | ||||||
|  | #include <api-hal-spi.h> | ||||||
|  | #include <api-hal-resources.h> | ||||||
|  | #include <api-hal-delay.h> | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | void hal_sd_detect_init(void) { | ||||||
|  |     // nothing to do
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void hal_sd_detect_set_low(void) { | ||||||
|  |     // nothing to do
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool hal_sd_detect(void) { | ||||||
|  |     bool result = false; | ||||||
|  | 
 | ||||||
|  |     // TODO open record
 | ||||||
|  |     const GpioPin* sd_cs_record = &sd_cs_gpio; | ||||||
|  | 
 | ||||||
|  |     // TODO: SPI manager
 | ||||||
|  |     api_hal_spi_lock(sd_fast_spi.spi); | ||||||
|  | 
 | ||||||
|  |     // configure pin as input
 | ||||||
|  |     gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); | ||||||
|  |     delay(1); | ||||||
|  | 
 | ||||||
|  |     // if gpio_read == 0 return true else return false
 | ||||||
|  |     result = !gpio_read(sd_cs_record); | ||||||
|  | 
 | ||||||
|  |     // configure pin back
 | ||||||
|  |     gpio_init_ex(sd_cs_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); | ||||||
|  |     gpio_write(sd_cs_record, 1); | ||||||
|  |     delay(1); | ||||||
|  | 
 | ||||||
|  |     // TODO: SPI manager
 | ||||||
|  |     api_hal_spi_unlock(sd_fast_spi.spi); | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
| @ -46,6 +46,8 @@ void NFC_SPI_Reconfigure(); | |||||||
| void SD_SPI_Reconfigure_Slow(); | void SD_SPI_Reconfigure_Slow(); | ||||||
| void SD_SPI_Reconfigure_Fast(); | void SD_SPI_Reconfigure_Fast(); | ||||||
| void CC1101_SPI_Reconfigure(); | void CC1101_SPI_Reconfigure(); | ||||||
|  | void SD_SPI_Bus_To_Down_State(); | ||||||
|  | void SD_SPI_Bus_To_Normal_State(); | ||||||
| /* USER CODE END Prototypes */ | /* USER CODE END Prototypes */ | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  | |||||||
| @ -92,7 +92,10 @@ | |||||||
| #include "string.h" | #include "string.h" | ||||||
| #include "stdio.h" | #include "stdio.h" | ||||||
| #include "spi.h" | #include "spi.h" | ||||||
| #include "api-hal-spi.h" | #include <api-hal-spi.h> | ||||||
|  | #include <api-hal-power.h> | ||||||
|  | #include <api-hal-delay.h> | ||||||
|  | #include <api-hal-sd.h> | ||||||
| 
 | 
 | ||||||
| /** @addtogroup BSP
 | /** @addtogroup BSP
 | ||||||
|   * @{ |   * @{ | ||||||
| @ -290,19 +293,40 @@ static uint8_t SD_ReadData(void); | |||||||
|   *         - MSD_ERROR: Sequence failed |   *         - MSD_ERROR: Sequence failed | ||||||
|   *         - MSD_OK: Sequence succeed |   *         - MSD_OK: Sequence succeed | ||||||
|   */ |   */ | ||||||
| uint8_t BSP_SD_Init(void) { | uint8_t BSP_SD_Init(bool reset_card) { | ||||||
|     /* Init to maximum slow speed */ |     /* Slow speed init */ | ||||||
|     // TODO: SPI manager
 | 
 | ||||||
|  |     /* TODO: SPI manager */ | ||||||
|     api_hal_spi_lock_device(&sd_slow_spi); |     api_hal_spi_lock_device(&sd_slow_spi); | ||||||
| 
 | 
 | ||||||
|  |     /* We must reset card in spi_lock context */ | ||||||
|  |     if(reset_card) { | ||||||
|  |         /* disable power and set low on all bus pins */ | ||||||
|  |         api_hal_power_disable_external_3_3v(); | ||||||
|  |         SD_SPI_Bus_To_Down_State(); | ||||||
|  |         hal_sd_detect_set_low(); | ||||||
|  |         delay(250); | ||||||
|  | 
 | ||||||
|  |         /* reinit bus and enable power */ | ||||||
|  |         SD_SPI_Bus_To_Normal_State(); | ||||||
|  |         hal_sd_detect_init(); | ||||||
|  |         api_hal_power_enable_external_3_3v(); | ||||||
|  |         delay(100); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /* Configure IO functionalities for SD pin */ |     /* Configure IO functionalities for SD pin */ | ||||||
|     SD_IO_Init(); |     SD_IO_Init(); | ||||||
| 
 | 
 | ||||||
|     /* SD detection pin is not physically mapped on the Adafruit shield */ |     /* SD detection pin is not physically mapped on the Adafruit shield */ | ||||||
|     SdStatus = SD_PRESENT; |     SdStatus = SD_PRESENT; | ||||||
|     uint8_t res = SD_GoIdleState(); |     uint8_t res = BSP_SD_ERROR; | ||||||
| 
 | 
 | ||||||
|     // TODO: SPI manager
 |     for(uint8_t i = 0; i < 128; i++) { | ||||||
|  |         res = SD_GoIdleState(); | ||||||
|  |         if(res == BSP_SD_OK) break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* TODO: SPI manager */ | ||||||
|     api_hal_spi_unlock_device(&sd_slow_spi); |     api_hal_spi_unlock_device(&sd_slow_spi); | ||||||
| 
 | 
 | ||||||
|     /* SD initialized and set to SPI mode properly */ |     /* SD initialized and set to SPI mode properly */ | ||||||
| @ -872,9 +896,10 @@ uint8_t SD_GetDataResponse(void) { | |||||||
|   */ |   */ | ||||||
| uint8_t SD_GoIdleState(void) { | uint8_t SD_GoIdleState(void) { | ||||||
|     SD_CmdAnswer_typedef response; |     SD_CmdAnswer_typedef response; | ||||||
|     __IO uint8_t counter = 0; |     __IO uint8_t counter; | ||||||
|     /* Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode and 
 |     /* Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode and 
 | ||||||
|      wait for In Idle State Response (R1 Format) equal to 0x01 */ |      wait for In Idle State Response (R1 Format) equal to 0x01 */ | ||||||
|  |     counter = 0; | ||||||
|     do { |     do { | ||||||
|         counter++; |         counter++; | ||||||
|         response = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95, SD_ANSWER_R1_EXPECTED); |         response = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95, SD_ANSWER_R1_EXPECTED); | ||||||
| @ -892,7 +917,9 @@ uint8_t SD_GoIdleState(void) { | |||||||
|     SD_IO_WriteByte(SD_DUMMY_BYTE); |     SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|     if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { |     if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { | ||||||
|         /* initialise card V1 */ |         /* initialise card V1 */ | ||||||
|  |         counter = 0; | ||||||
|         do { |         do { | ||||||
|  |             counter++; | ||||||
|             /* initialise card V1 */ |             /* initialise card V1 */ | ||||||
|             /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ |             /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ | ||||||
|             response = SD_SendCmd(SD_CMD_APP_CMD, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); |             response = SD_SendCmd(SD_CMD_APP_CMD, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
| @ -903,11 +930,16 @@ uint8_t SD_GoIdleState(void) { | |||||||
|             response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); |             response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|             SD_IO_CSState(1); |             SD_IO_CSState(1); | ||||||
|             SD_IO_WriteByte(SD_DUMMY_BYTE); |             SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|  |             if(counter >= SD_MAX_TRY) { | ||||||
|  |                 return BSP_SD_ERROR; | ||||||
|  |             } | ||||||
|         } while(response.r1 == SD_R1_IN_IDLE_STATE); |         } while(response.r1 == SD_R1_IN_IDLE_STATE); | ||||||
|         flag_SDHC = 0; |         flag_SDHC = 0; | ||||||
|     } else if(response.r1 == SD_R1_IN_IDLE_STATE) { |     } else if(response.r1 == SD_R1_IN_IDLE_STATE) { | ||||||
|         /* initialise card V2 */ |         /* initialise card V2 */ | ||||||
|  |         counter = 0; | ||||||
|         do { |         do { | ||||||
|  |             counter++; | ||||||
|             /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ |             /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ | ||||||
|             response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); |             response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|             SD_IO_CSState(1); |             SD_IO_CSState(1); | ||||||
| @ -917,10 +949,15 @@ uint8_t SD_GoIdleState(void) { | |||||||
|             response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x40000000, 0xFF, SD_ANSWER_R1_EXPECTED); |             response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x40000000, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|             SD_IO_CSState(1); |             SD_IO_CSState(1); | ||||||
|             SD_IO_WriteByte(SD_DUMMY_BYTE); |             SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|  |             if(counter >= SD_MAX_TRY) { | ||||||
|  |                 return BSP_SD_ERROR; | ||||||
|  |             } | ||||||
|         } while(response.r1 == SD_R1_IN_IDLE_STATE); |         } while(response.r1 == SD_R1_IN_IDLE_STATE); | ||||||
| 
 | 
 | ||||||
|         if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { |         if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { | ||||||
|  |             counter = 0; | ||||||
|             do { |             do { | ||||||
|  |                 counter++; | ||||||
|                 /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ |                 /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ | ||||||
|                 response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); |                 response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|                 SD_IO_CSState(1); |                 SD_IO_CSState(1); | ||||||
| @ -933,6 +970,9 @@ uint8_t SD_GoIdleState(void) { | |||||||
|                     SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); |                     SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); | ||||||
|                 SD_IO_CSState(1); |                 SD_IO_CSState(1); | ||||||
|                 SD_IO_WriteByte(SD_DUMMY_BYTE); |                 SD_IO_WriteByte(SD_DUMMY_BYTE); | ||||||
|  |                 if(counter >= SD_MAX_TRY) { | ||||||
|  |                     return BSP_SD_ERROR; | ||||||
|  |                 } | ||||||
|             } while(response.r1 == SD_R1_IN_IDLE_STATE); |             } while(response.r1 == SD_R1_IN_IDLE_STATE); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -46,6 +46,7 @@ | |||||||
| 
 | 
 | ||||||
| /* Includes ------------------------------------------------------------------*/ | /* Includes ------------------------------------------------------------------*/ | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| /** @addtogroup BSP
 | /** @addtogroup BSP
 | ||||||
|   * @{ |   * @{ | ||||||
| @ -208,7 +209,7 @@ typedef struct | |||||||
| /** @defgroup STM32_ADAFRUIT_SD_Exported_Functions
 | /** @defgroup STM32_ADAFRUIT_SD_Exported_Functions
 | ||||||
|   * @{ |   * @{ | ||||||
|   */    |   */    | ||||||
| uint8_t BSP_SD_Init(void); | uint8_t BSP_SD_Init(bool reset_card); | ||||||
| uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); | uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); | ||||||
| uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); | uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); | ||||||
| uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); | uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); | ||||||
|  | |||||||
| @ -163,10 +163,9 @@ void MX_GPIO_Init(void) | |||||||
| 
 | 
 | ||||||
|   /*Configure GPIO pin : PtPin */ |   /*Configure GPIO pin : PtPin */ | ||||||
|   GPIO_InitStruct.Pin = SD_CS_Pin; |   GPIO_InitStruct.Pin = SD_CS_Pin; | ||||||
|   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; | ||||||
|   GPIO_InitStruct.Pull = GPIO_NOPULL; |   GPIO_InitStruct.Pull = GPIO_NOPULL; | ||||||
|   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; |   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; | ||||||
|   GPIO_InitStruct.Alternate = GPIO_AF6_LSCO; |  | ||||||
|   HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct); |   HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct); | ||||||
| 
 | 
 | ||||||
|   /*Configure GPIO pin : PtPin */ |   /*Configure GPIO pin : PtPin */ | ||||||
|  | |||||||
| @ -339,6 +339,36 @@ void Enable_SPI(SPI_HandleTypeDef* spi_instance){ | |||||||
|     __HAL_SPI_ENABLE(spi_instance); |     __HAL_SPI_ENABLE(spi_instance); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void SD_SPI_Bus_To_Down_State(){ | ||||||
|  |   GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||||
|  |   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; | ||||||
|  | 
 | ||||||
|  |   GPIO_InitStruct.Pin = GPIO_PIN_2; | ||||||
|  |   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; | ||||||
|  |   GPIO_InitStruct.Pull = GPIO_NOPULL; | ||||||
|  |   HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); | ||||||
|  | 
 | ||||||
|  |   GPIO_InitStruct.Pin = SPI_D_MOSI_Pin; | ||||||
|  |   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; | ||||||
|  |   GPIO_InitStruct.Pull = GPIO_NOPULL; | ||||||
|  |   HAL_GPIO_Init(SPI_D_MOSI_GPIO_Port, &GPIO_InitStruct); | ||||||
|  | 
 | ||||||
|  |   GPIO_InitStruct.Pin = SPI_D_SCK_Pin; | ||||||
|  |   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; | ||||||
|  |   GPIO_InitStruct.Pull = GPIO_NOPULL; | ||||||
|  |   HAL_GPIO_Init(SPI_D_SCK_GPIO_Port, &GPIO_InitStruct); | ||||||
|  | 
 | ||||||
|  |   HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET); | ||||||
|  |   HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); | ||||||
|  |   HAL_GPIO_WritePin(SPI_D_MOSI_GPIO_Port, SPI_D_MOSI_Pin, GPIO_PIN_RESET); | ||||||
|  |   HAL_GPIO_WritePin(SPI_D_SCK_GPIO_Port, SPI_D_SCK_Pin, GPIO_PIN_RESET); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SD_SPI_Bus_To_Normal_State(){ | ||||||
|  |   HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET); | ||||||
|  |   HAL_SPI_MspInit(&SPI_SD_HANDLE); | ||||||
|  | } | ||||||
| /* USER CODE END 1 */ | /* USER CODE END 1 */ | ||||||
| 
 | 
 | ||||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||||
|  | |||||||
| @ -20,33 +20,6 @@ void hal_gpio_init( | |||||||
|     HAL_GPIO_Init(gpio->port, &GPIO_InitStruct); |     HAL_GPIO_Init(gpio->port, &GPIO_InitStruct); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool hal_gpio_read_sd_detect(void) { |  | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     // TODO open record
 |  | ||||||
|     const GpioPin* sd_cs_record = &sd_cs_gpio; |  | ||||||
| 
 |  | ||||||
|     // TODO: SPI manager
 |  | ||||||
|     api_hal_spi_lock(sd_fast_spi.spi); |  | ||||||
| 
 |  | ||||||
|     // configure pin as input
 |  | ||||||
|     gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); |  | ||||||
|     delay(1); |  | ||||||
| 
 |  | ||||||
|     // if gpio_read == 0 return true else return false
 |  | ||||||
|     result = !gpio_read(sd_cs_record); |  | ||||||
| 
 |  | ||||||
|     // configure pin back
 |  | ||||||
|     gpio_init_ex(sd_cs_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); |  | ||||||
|     gpio_write(sd_cs_record, 1); |  | ||||||
|     delay(1); |  | ||||||
| 
 |  | ||||||
|     // TODO: SPI manager
 |  | ||||||
|     api_hal_spi_unlock(sd_fast_spi.spi); |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void enable_cc1101_irq() { | void enable_cc1101_irq() { | ||||||
|     HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0); |     HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0); | ||||||
|     HAL_NVIC_EnableIRQ(EXTI4_IRQn); |     HAL_NVIC_EnableIRQ(EXTI4_IRQn); | ||||||
|  | |||||||
| @ -68,8 +68,6 @@ static inline bool hal_gpio_read(const GpioPin* gpio) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool hal_gpio_read_sd_detect(void); |  | ||||||
| 
 |  | ||||||
| void enable_cc1101_irq(); | void enable_cc1101_irq(); | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ | |||||||
| #include <stm32wbxx_ll_pwr.h> | #include <stm32wbxx_ll_pwr.h> | ||||||
| #include <stm32wbxx_ll_hsem.h> | #include <stm32wbxx_ll_hsem.h> | ||||||
| #include <stm32wbxx_ll_cortex.h> | #include <stm32wbxx_ll_cortex.h> | ||||||
|  | #include <stm32wbxx_ll_gpio.h> | ||||||
| 
 | 
 | ||||||
| #include <main.h> | #include <main.h> | ||||||
| #include <hw_conf.h> | #include <hw_conf.h> | ||||||
| @ -195,3 +196,11 @@ void api_hal_power_dump_state(string_t buffer) { | |||||||
|         bq25896_get_ntc_mpct() |         bq25896_get_ntc_mpct() | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void api_hal_power_enable_external_3_3v(){ | ||||||
|  |     LL_GPIO_SetOutputPin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void api_hal_power_disable_external_3_3v(){ | ||||||
|  |     LL_GPIO_ResetOutputPin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin); | ||||||
|  | } | ||||||
| @ -25,7 +25,6 @@ const InputPin input_pins[] = { | |||||||
| 
 | 
 | ||||||
| const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); | const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); | ||||||
| 
 | 
 | ||||||
| const GpioPin sd_cs_gpio = {SD_CS_GPIO_Port, SD_CS_Pin}; |  | ||||||
| const GpioPin vibro_gpio = {VIBRO_GPIO_Port, VIBRO_Pin}; | const GpioPin vibro_gpio = {VIBRO_GPIO_Port, VIBRO_Pin}; | ||||||
| const GpioPin ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin}; | const GpioPin ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin}; | ||||||
| const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin}; | const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin}; | ||||||
|  | |||||||
| @ -53,7 +53,6 @@ typedef struct { | |||||||
| extern const InputPin input_pins[]; | extern const InputPin input_pins[]; | ||||||
| extern const size_t input_pins_count; | extern const size_t input_pins_count; | ||||||
| 
 | 
 | ||||||
| extern const GpioPin sd_cs_gpio; |  | ||||||
| extern const GpioPin vibro_gpio; | extern const GpioPin vibro_gpio; | ||||||
| extern const GpioPin ibutton_gpio; | extern const GpioPin ibutton_gpio; | ||||||
| extern const GpioPin cc1101_g0_gpio; | extern const GpioPin cc1101_g0_gpio; | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								firmware/targets/f5/api-hal/api-hal-sd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								firmware/targets/f5/api-hal/api-hal-sd.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | #include "api-hal-sd.h" | ||||||
|  | #include <stm32wbxx_ll_gpio.h> | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | void hal_sd_detect_init(void) { | ||||||
|  |     // low speed input with pullup
 | ||||||
|  |     LL_GPIO_SetPinMode(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_MODE_INPUT); | ||||||
|  |     LL_GPIO_SetPinSpeed(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_SPEED_FREQ_LOW); | ||||||
|  |     LL_GPIO_SetPinPull(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_PULL_UP); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void hal_sd_detect_set_low(void) { | ||||||
|  |     // low speed input with pullup
 | ||||||
|  |     LL_GPIO_SetPinMode(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_MODE_OUTPUT); | ||||||
|  |     LL_GPIO_SetPinOutputType(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_OUTPUT_OPENDRAIN); | ||||||
|  |     LL_GPIO_ResetOutputPin(SD_CD_GPIO_Port, SD_CD_Pin); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool hal_sd_detect(void) { | ||||||
|  |     bool result = !(LL_GPIO_IsInputPinSet(SD_CD_GPIO_Port, SD_CD_Pin)); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG