diff --git a/demos/ARMCM3-STM32F103ZG-FATFS/iar/ch.ewp b/demos/ARMCM3-STM32F103ZG-FATFS/iar/ch.ewp
index 711931abd..a66a70295 100644
--- a/demos/ARMCM3-STM32F103ZG-FATFS/iar/ch.ewp
+++ b/demos/ARMCM3-STM32F103ZG-FATFS/iar/ch.ewp
@@ -1890,6 +1890,9 @@
$PROJ_DIR$\..\..\..\os\kernel\include\ch.h
+
+ $PROJ_DIR$\..\..\..\os\kernel\include\chbsem.h
+
$PROJ_DIR$\..\..\..\os\kernel\include\chcond.h
@@ -1902,6 +1905,9 @@
$PROJ_DIR$\..\..\..\os\kernel\include\chevents.h
+
+ $PROJ_DIR$\..\..\..\os\kernel\include\chfiles.h
+
$PROJ_DIR$\..\..\..\os\kernel\include\chheap.h
diff --git a/demos/ARMCM3-STM32F103ZG-FATFS/main.c b/demos/ARMCM3-STM32F103ZG-FATFS/main.c
index 5e1ac9863..374cf7c4a 100644
--- a/demos/ARMCM3-STM32F103ZG-FATFS/main.c
+++ b/demos/ARMCM3-STM32F103ZG-FATFS/main.c
@@ -22,6 +22,89 @@
#include "hal.h"
#include "test.h"
+/*===========================================================================*/
+/* Card insertion monitor. */
+/*===========================================================================*/
+
+#define SDC_POLLING_INTERVAL 10
+#define SDC_POLLING_DELAY 10
+
+/**
+ * @brief Card monitor timer.
+ */
+static VirtualTimer tmr;
+
+/**
+ * @brief Debounce counter.
+ */
+static unsigned cnt;
+
+/**
+ * @brief Card event sources.
+ */
+static EventSource inserted_event, removed_event;
+
+/**
+ * @brief Inserion monitor function.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+static bool_t sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+
+ return TRUE;
+}
+
+/**
+ * @brief Inserion monitor timer callback function.
+ *
+ * @param[in] p pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+static void tmrfunc(void *p) {
+ SDCDriver *sdcp = p;
+
+ if (cnt > 0) {
+ if (sdcIsCardInserted(sdcp)) {
+ if (--cnt == 0) {
+ chEvtBroadcastI(&inserted_event);
+ }
+ }
+ else
+ cnt = SDC_POLLING_INTERVAL;
+ }
+ else {
+ if (!sdcIsCardInserted(sdcp)) {
+ cnt = SDC_POLLING_INTERVAL;
+ chEvtBroadcastI(&removed_event);
+ }
+ }
+ chVTSetI(&tmr, MS2ST(SDC_POLLING_DELAY), tmrfunc, sdcp);
+}
+
+/**
+ * @brief Polling monitor start.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+static void tmr_init(SDCDriver *sdcp) {
+
+ chEvtInit(&inserted_event);
+ chEvtInit(&removed_event);
+ chSysLock();
+ cnt = SDC_POLLING_INTERVAL;
+ chVTSetI(&tmr, MS2ST(SDC_POLLING_DELAY), tmrfunc, sdcp);
+ chSysUnlock();
+}
+
+/*===========================================================================*/
+/* Main and generic code. */
+/*===========================================================================*/
+
/*
* Red LED blinker thread, times are in milliseconds.
*/
@@ -65,6 +148,11 @@ int main(void) {
*/
sdStart(&SD1, NULL);
+ /*
+ * Activates the card insertion monitor.
+ */
+ tmr_init(&SDCD1);
+
/*
* Creates the blinker thread.
*/
diff --git a/os/hal/include/sdc.h b/os/hal/include/sdc.h
index 3f0634fc5..afc3a6aba 100644
--- a/os/hal/include/sdc.h
+++ b/os/hal/include/sdc.h
@@ -173,6 +173,22 @@ typedef enum {
*/
#define sdcGetDriverState(sdcp) ((sdcp)->state)
+/**
+ * @brief Returns the card insertion status.
+ * @note This macro wraps a low level function named
+ * @p sdc_lld_is_card_inserted(), this function must be
+ * provided by the application because it is not part of the
+ * SDC driver.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @return The card state.
+ * @retval FALSE card not inserted.
+ * @retval TRUE card inserted.
+ *
+ * @api
+ */
+#define sdcIsCardInserted(sdcp) (sdc_lld_is_card_inserted(sdcp))
+
/**
* @brief Returns the write protect status.
* @note This macro wraps a low level function named