Estoy trabajando con una placa de evaluación STM32 L476RG en un proyecto. El objetivo actualmente es utilizar la biblioteca de almacenamiento masivo de STM para escribir datos en flash a través de USB. Tengo la biblioteca USB funcionando correctamente (simplemente leyendo y escribiendo datos desde/a la RAM para empezar), pero encontré un problema extraño al usar flash.
Si escribo en la memoria flash en la función STORAGE_Init_FS (usando HAL_FLASH_Program(....)), puedo escribir en la memoria flash perfectamente. Borro la página, le escribo datos arbitrarios y aparece en la vista de memoria del depurador.
Sin embargo, si trato de hacer exactamente lo mismo en STORAGE_Write_FS (intenté con línea por línea, el mismo código), entonces la operación flash devuelve un error y nunca escribe ningún dato.
Aquí están las porciones de código relevantes:
{
/* USER CODE BEGIN 2 */
USB_Flash_Init();
return (USBD_OK);
/* USER CODE END 2 */
}
HAL_StatusTypeDef USB_Flash_Init() {
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_FLASH_CLK_ENABLE();
/* Clear flash flags */
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
HAL_FLASH_Lock();
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, 0x8080000, 0x0001);
HAL_FLASH_Lock();
return HAL_OK;
}
En el código anterior, los datos 0x0001 se escriben correctamente en la dirección de memoria 0x8080000. (La llamada de borrado no está ahí, pero la página ha sido borrada).
Sin embargo, en la siguiente función,
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_FLASH_CLK_ENABLE();
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
HAL_FLASH_Lock();
HAL_FLASH_Unlock();
FLASH_PageErase(0, FLASH_BANK_2);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, 0x8080000, 0x0001);
FLASH_PageErase(0, FLASH_BANK_2);
HAL_FLASH_Lock();
return (USBD_OK);
/* USER CODE END 7 */
}
Los datos se borran correctamente (ver la dirección de memoria a través del depurador), pero luego nunca se escriben, permanecen 0xFFFFFFFF. Sé que algunas de las cosas de inicialización ya se habían hecho, pero quería estar seguro de que no era la causa, así que lo incluí allí también. Lo único en lo que realmente puedo pensar sería que la pila podría no tener suficiente espacio (poco probable con la gran cantidad de memoria que tiene). Para verificar que esta no era la causa, intenté sacar mi búfer de 2k (que no se muestra aquí) fuera de la función para que ya no fuera una variable local y aumentar los tamaños de pila y montón a 0x4096 (excesivo) en la RAM .ld.
Ninguno cambió el comportamiento. Cualquiera con el que he hablado ha estado perdido en cuanto a la causa de esto. ¿Qué podría estar haciendo mal?
Recibo dos errores cuando compruebo HAL_FLASH_CheckError() (puede que no sea el nombre exacto de la función), 0xA0, que corresponde a HAL_FLASH_ERROR_PGS y HAL_FLASH_ERROR_PGA, secuencia de programación y errores de alineación de programación, respectivamente. No estoy seguro de que estos errores sean relevantes, considerando que las llamadas a funciones reales y la configuración son idénticas, solo el alcance es diferente.
Si alguien tiene algún consejo, ¡me encantaría escucharlo! Con suerte, solo me falta algún registro de control o bit en alguna parte.
Parece que el problema real es que FLASH_PECR_ERASE
(o al menos eso es lo que se llama en el L0) se deja establecido por las típicas rutinas de borrado de flash. Esto hace que los intentos posteriores del programa sean una mezcla extraña y quizás inválida de programa y operación de borrado. Como se menciona en los comentarios a continuación, he visto esto anteriormente en un STM32L0, y parece ser un problema con el STM32L4 aquí también.
Siguen ideas originales y aparentemente irrelevantes
Flash está escribiendo bien en main() y donde sea que lo intente, es solo en esta función de escritura USB que falla.
¿Por qué no se puede hacer esto en un contexto de interrupción? Ambas funciones que he demostrado se llaman en una interrupción USB administrada por las bibliotecas de STM.
Tomando al pie de la letra la creencia (quizás incorrecta) de que esto se está llamando desde un contexto de interrupción, definitivamente no puede escribir en flash desde una interrupción por medios ordinarios. Escribir en la memoria flash es un proceso muy complejo, una desviación real de la operación ordinaria de un chip que se supone que los chips casi nunca realizan, y que también consume mucho tiempo.
Deberá almacenar en caché la intención de realizar una escritura (guardar el deseo y los datos), realizarla más tarde desde el ciclo principal y luego poner en cola una respuesta de éxito o falla para enviar de vuelta a través de USB (es decir, aceptar los datos inmediatamente, pero no responda si la escritura funcionó o no hasta que la haya completado). Recuerde establecer comunicación entre la interrupción y el ciclo principal a través de banderas atómicas seguras, o use una sección crítica apropiadamente breve para hacer una copia de cualquier cosa no atómica. Probablemente necesitará bloquear más modificaciones del búfer de datos desde la interrupción hasta que haya terminado la escritura, si no puede hacerlo en el nivel del búfer USB, es posible que necesite DMA desde un búfer USB en otra parte de la RAM y luego escribir desde allí.
Los ejemplos de almacenamiento masivo USB son muy comunes. Probablemente pueda aprender cosas útiles sobre cómo hacer el desacoplamiento necesario de un ejemplo respaldado por flash SPI en lugar de interno o de uno para un STM32 diferente si el bloque funcional USB tiene similitudes significativas en su arquitectura con respecto al almacenamiento en búfer, etc.
Si realmente se llama desde una interrupción, es un código de ejemplo desafortunado STORAGE_Write_FS()
. Puede ser que haya partes de la arquitectura del ejemplo que aún no se entiendan lo suficiente; si dan un ejemplo respaldado por almacenamiento no volátil real (en lugar de falsificarlo con un poco de RAM), sería necesario un examen detallado de eso. llave.
Actualización: el problema era el uso de la función FLASH_PageErase(), que no restablece los bits de control adecuados para que el flash permita volver a escribir. Simplemente coincidió con el orden de las llamadas de función que no estaba borrando la página hasta la segunda llamada.
Estoy seguro de que revisar la documentación arrojará los bits relevantes que deben restablecerse, pero en mi caso simplemente cambié a la función HAL_FLASHEx_Erase. Dejo esto aquí en caso de que alguien se encuentre con un problema similar.
chris stratton
rom1nux
kbrown323
kbrown323
kbrown323