Converting Mac Roman character to equivalent UTF-8 - unicode

I have been given some HTML files that use the Mac OS Roman file encoding. The files have French text, but in an editor many of the diacritical chars look strange (i.e. non French)
Si cette option est sÈlectionnÈe, <removed> tentera de communiquer avec votre tÈlescope seulement ‡ líaide díun ...
The capital E with accent does display properly in the browser as é as do the other strange characters.
I also have some UTF-8 French files that look normal in an editor (é looks like é). What I'd like to do is convert all the Mac Roman files to UTF-8 for easier maintenance.
Simply changing the file encoding in the editor doesn't do this. The strange characters are still strange.
Short of making a conversion dictionary and doing a Find/Replace on all the files, is there a way to do this?

If your editor isn’t showing it correctly when you specify the encoding, you have given it the wrong encoding. You need to figure what encoding you really have.
You appear to have a byte valued 0xE9 where you need a Unicode LATIN SMALL LETTER E WITH ACUTE character. A MacRoman 0xE9 byte is a LATIN CAPITAL LETTER E WITH GRAVE character, which is what your editor is displaying because you said it was MacRoman. But it is not.
However, Unicode code point U+00E9 is indeed LATIN SMALL LETTER E WITH ACUTE.
Therefore, it is not MacRoman that you have there, but almost certainly ISO-8859-1 or ISO-8859-15.
So use something like
$ iconv -f ISO-8859-1 -t UTF-8 < input.latin1 > output.utf8
to do the conversion.

To actually answer the question "Converting Mac Roman character to equivalent UTF-8"
Convert the encoding of the file from Mac OS Roman to UTF-8:
$ iconv -f macintosh -t UTF-8 < INPUT_FILE_PATH > OUTPUT_FILE_PATH

To convert lots of old java code files in directory tree, this worked for me.
Observe that the command will change files recursively in all directories from where you did cd into. Make sure you are positioned in the right directory and that you have a backup of your files, and computer, first. When you know what you are doing, correct the rm statement. Hope this can help somebody, took me hours to correct the tiny details to get this working.:
cd /tmp
pwd
find . -name "*.java" -exec bash -c 'mv $1 $1.WXY; iconv -f MAC -t UTF8 $1.WXY > $1; rm $1.WXYY' sh {} \;

C++ code:
string ConvertMacRomanCharacterToUtf8( unsigned char c )
{
static vector<string> strings
// switch ( c )
{
/* case 0x80: return */ "\xC3\x84", // A umlaut
/* case 0x81: return */ "\xC3\x85", // A circle
/* case 0x82: return */ "\xC3\x87", // C cedilla
/* case 0x83: return */ "\xC3\x89", // E accent
/* case 0x84: return */ "\xC3\x91", // N tilde
/* case 0x85: return */ "\xC3\x96", // O umlaut
/* case 0x86: return */ "\xC3\x9C", // U umlaut
/* case 0x87: return */ "\xC3\xA1", // a accent
/* case 0x88: return */ "\xC3\xA0", // a grave
/* case 0x89: return */ "\xC3\xA2", // a circumflex
/* case 0x8A: return */ "\xC3\xA4", // a umlaut
/* case 0x8B: return */ "\xC3\xA3", // a tilde
/* case 0x8C: return */ "\xC3\xA5", // a circle
/* case 0x8D: return */ "\xC3\xA7", // c cedilla
/* case 0x8E: return */ "\xC3\xA9", // e accent
/* case 0x8F: return */ "\xC3\xA8", // e grave
/* case 0x90: return */ "\xC3\xAA", // e circumflex
/* case 0x91: return */ "\xC3\xAB", // e umlaut
/* case 0x92: return */ "\xC3\xAD", // i accent
/* case 0x93: return */ "\xC3\xAC", // i grave
/* case 0x94: return */ "\xC3\xAE", // i circumflex
/* case 0x95: return */ "\xC3\xAF", // i umlaut
/* case 0x96: return */ "\xC3\xB1", // n tilde
/* case 0x97: return */ "\xC3\xB3", // o accent
/* case 0x98: return */ "\xC3\xB2", // o grave
/* case 0x99: return */ "\xC3\xB4", // o circumflex
/* case 0x9A: return */ "\xC3\xB6", // o umlaut
/* case 0x9B: return */ "\xC3\xB5", // o tilde
/* case 0x9C: return */ "\xC3\xBA", // u accent
/* case 0x9D: return */ "\xC3\xB9", // u grave
/* case 0x9E: return */ "\xC3\xBB", // u circumflex
/* case 0x9F: return */ "\xC3\xBC", // u tilde
/* case 0xA0: return */ "\xE2\x80\xA0", // cross
/* case 0xA1: return */ "\xC2\xB0", // degree
/* case 0xA2: return */ "\xC2\xA2", // cents
/* case 0xA3: return */ "\xC2\xA3", // pounds
/* case 0xA4: return */ "\xC2\xA7", // section
/* case 0xA5: return */ "\xE2\x80\xA2", // bullet
/* case 0xA6: return */ "\xC2\xB6", // pilcrow
/* case 0xA7: return */ "\xC3\x9F", // german sharp S
/* case 0xA8: return */ "\xC2\xAE", // registered
/* case 0xA9: return */ "\xC2\xA9", // copyright
/* case 0xAA: return */ "\xE2\x84\xA2", // TM
/* case 0xAB: return */ "\xC2\xB4", // back tick
/* case 0xAC: return */ "\xC2\xA8", // umlaut
/* case 0xAD: return */ "\xE2\x89\xA0", // not equal (not in Windows 1252)
/* case 0xAE: return */ "\xC3\x86", // AE
/* case 0xAF: return */ "\xC3\x98", // O slash
/* case 0xB0: return */ "\xE2\x88\x9E", // infinity (not in Windows 1252)
/* case 0xB1: return */ "\xC2\xB1", // plus or minus
/* case 0xB2: return */ "\xE2\x89\xA4", // less than or equal (not in Windows 1252)
/* case 0xB3: return */ "\xE2\x89\xA5", // greater than or equal (not in Windows 1252)
/* case 0xB4: return */ "\xC2\xA5", // yen
/* case 0xB5: return */ "\xC2\xB5", // mu
/* case 0xB6: return */ "\xE2\x88\x82", // derivative (not in Windows 1252)
/* case 0xB7: return */ "\xE2\x88\x91", // large sigma (not in Windows 1252)
/* case 0xB8: return */ "\xE2\x88\x8F", // large pi (not in Windows 1252)
/* case 0xB9: return */ "\xCF\x80", // small pi (not in Windows 1252)
/* case 0xBA: return */ "\xE2\x88\xAB", // integral (not in Windows 1252)
/* case 0xBB: return */ "\xC2\xAA", // feminine ordinal
/* case 0xBC: return */ "\xC2\xBA", // masculine ordinal
/* case 0xBD: return */ "\xCE\xA9", // large ohm (not in Windows 1252)
/* case 0xBE: return */ "\xC3\xA6", // ae
/* case 0xBF: return */ "\xC3\xB8", // o slash
/* case 0xC0: return */ "\xC2\xBF", // inverted question mark
/* case 0xC1: return */ "\xC2\xA1", // inverted exclamation mark
/* case 0xC2: return */ "\xC2\xAC", // not
/* case 0xC3: return */ "\xE2\x88\x9A", // root (not in Windows 1252)
/* case 0xC4: return */ "\xC6\x92", // function
/* case 0xC5: return */ "\xE2\x89\x88", // approximately equal (not in Windows 1252)
/* case 0xC6: return */ "\xE2\x88\x86", // large delta (not in Windows 1252)
/* case 0xC7: return */ "\xC2\xAB", // open angle quotation mark
/* case 0xC8: return */ "\xC2\xBB", // close angle quotation mark
/* case 0xC9: return */ "\xE2\x80\xA6", // ellipsis
/* case 0xCA: return */ "\xC2\xA0", // NBSP
/* case 0xCB: return */ "\xC3\x80", // A grave
/* case 0xCC: return */ "\xC3\x83", // A tilde
/* case 0xCD: return */ "\xC3\x95", // O tilde
/* case 0xCE: return */ "\xC5\x92", // OE
/* case 0xCF: return */ "\xC5\x93", // oe
/* case 0xD0: return */ "\xE2\x80\x93", // en dash
/* case 0xD1: return */ "\xE2\x80\x94", // em dash
/* case 0xD2: return */ "\xE2\x80\x9C", // open smart double quote
/* case 0xD3: return */ "\xE2\x80\x9D", // close smart double quote
/* case 0xD4: return */ "\xE2\x80\x98", // open smart single quote
/* case 0xD5: return */ "\xE2\x80\x99", // close smart single quote
/* case 0xD6: return */ "\xC3\xB7", // divided
/* case 0xD7: return */ "\xE2\x97\x8A", // diamond (not in Windows 1252)
/* case 0xD8: return */ "\xC3\xBF", // y umlaut
/* case 0xD9: return */ "\xC5\xB8", // Y umlaut
/* case 0xDA: return */ "\xE2\x81\x84", // big slash (not in Windows 1252)
/* case 0xDB: return */ "\xE2\x82\xAC", // euro (not in Windows 1252)
/* case 0xDC: return */ "\xE2\x80\xB9", // open angle single quote
/* case 0xDD: return */ "\xE2\x80\xBA", // close angle single quote
/* case 0xDE: return */ "\xEF\xAC\x81", // fi ligature (not in Windows 1252)
/* case 0xDF: return */ "\xEF\xAC\x82", // fl ligature (not in Windows 1252)
/* case 0xE0: return */ "\xE2\x80\xA1", // double dagger
/* case 0xE1: return */ "\xC2\xB7", // interpunct
/* case 0xE2: return */ "\xE2\x80\x9A", // inverted smart single quote
/* case 0xE3: return */ "\xE2\x80\x9E", // inverted smart double quote
/* case 0xE4: return */ "\xE2\x80\xB0", // per mille
/* case 0xE5: return */ "\xC3\x82", // A circumflex
/* case 0xE6: return */ "\xC3\x8A", // E circumflex
/* case 0xE7: return */ "\xC3\x81", // A accent
/* case 0xE8: return */ "\xC3\x8B", // E umlaut
/* case 0xE9: return */ "\xC3\x88", // E grave
/* case 0xEA: return */ "\xC3\x8D", // I accent
/* case 0xEB: return */ "\xC3\x8E", // I circumflex
/* case 0xEC: return */ "\xC3\x8F", // I umlaut
/* case 0xED: return */ "\xC3\x8C", // I grave
/* case 0xEE: return */ "\xC3\x93", // O accent
/* case 0xEF: return */ "\xC3\x94", // O circumflex
/* case 0xF0: return */ "\xEF\xA3\xBF", // box (not in Windows 1252)
/* case 0xF1: return */ "\xC3\x92", // O grave
/* case 0xF2: return */ "\xC3\x9A", // U accent
/* case 0xF3: return */ "\xC3\x9B", // U circumflex
/* case 0xF4: return */ "\xC3\x99", // U grave
/* case 0xF5: return */ "\xC4\xB1", // dotless i ligature (not in Windows 1252)
/* case 0xF6: return */ "\xCB\x86", // circumflex
/* case 0xF7: return */ "\xCB\x9C", // tilde
/* case 0xF8: return */ "\xC2\xAF", // macron
/* case 0xF9: return */ "\xCB\x98", // breve (not in Windows 1252)
/* case 0xFA: return */ "\xCB\x99", // raised dot (not in Windows 1252)
/* case 0xFB: return */ "\xCB\x9A", // ring
/* case 0xFC: return */ "\xC2\xB8", // cedilla
/* case 0xFD: return */ "\xCB\x9D", // double acute accent (not in Windows 1252)
/* case 0xFE: return */ "\xCB\x9B", // ogonek (not in Windows 1252)
/* case 0xFF: return */ "\xCB\x87", // caron (not in Windows 1252)
};
if ( c >= 0x80 )
{
return strings[ c - 0x80 ];
}
return string( 1, c );
}

Related

EEPROM emulator on STM32L053

I known that isn't normal to use EEPROM emulator on a STM32L053, because it has is own EEPROM, but nowadays with the chip shortage, i was forcedto use an alternative MCU (STM32L053R8T6) instead of the "original design" (STM32F030C8T6), so i want to use the same code for both MCU, so the EEPROM emulator on the STM32L053R8T6.
But i'm having some difficulty using the EEPROM emulator on the STM32L053, the compiler didn't give any error, and the code run normmally, but didn't save any value to the EEPROM.
Header File:
#define ADDR_FLASH_PAGE_60 ((uint32_t)0x0800F000) /* Base # of Page 60, 1 Kbytes */
#define ADDR_FLASH_PAGE_61 ((uint32_t)0x0800F400) /* Base # of Page 61, 1 Kbytes */
#define ADDR_FLASH_PAGE_62 ((uint32_t)0x0800F800) /* Base # of Page 62, 1 Kbytes */
/* Define the size of the sectors to be used */
#define PAGE_SIZE (uint32_t) FLASH_PAGE_SIZE /* Page size */
/* EEPROM start address in Flash */
#define EEPROM_START_ADDRESS ((uint32_t) ADDR_FLASH_PAGE_60) /* EEPROM emulation start address */
/* Pages 0 and 1 base and end addresses */
#define PAGE0_BASE_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
#define PAGE0_END_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
#define PAGE1_BASE_ADDRESS ((uint32_t)(ADDR_FLASH_PAGE_61))
#define PAGE1_END_ADDRESS ((uint32_t)(ADDR_FLASH_PAGE_61 + PAGE_SIZE - 1))
/* Used Flash pages for EEPROM emulation */
#define PAGE0 ((uint16_t) 0x0000)
#define PAGE1 ((uint16_t)((PAGE1_BASE_ADDRESS-PAGE0_BASE_ADDRESS)/PAGE_SIZE)) /* Virtual page nb between PAGE0_BASE_ADDRESS & PAGE1_BASE_ADDRESS*/
/* No valid page define */
#define NO_VALID_PAGE ((uint16_t)0x00AB)
/* Page status definitions */
#define ERASED ((uint16_t)0xFFFF) /* Page is empty */
#define RECEIVE_DATA ((uint16_t)0xEEEE) /* Page is marked to receive data */
#define VALID_PAGE ((uint16_t)0x0000) /* Page containing valid data */
/* Valid pages in read and write defines */
#define READ_FROM_VALID_PAGE ((uint8_t)0x00)
#define WRITE_IN_VALID_PAGE ((uint8_t)0x01)
/* Page full define */
#define PAGE_FULL ((uint8_t)0x80)
void EE_ReadData(void);
uint16_t EE_Init(void);
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);
#endif /* __EEPROM_H */
EEPROM Write Variable Function:
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data)
{
uint16_t Status = 0;
/* Write the variable virtual address and value in the EEPROM */
Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
/* In case the EEPROM active page is full */
if (Status == PAGE_FULL)
{
/* Perform Page transfer */
Status = EE_PageTransfer(VirtAddress, Data);
}
/* Return last operation status */
return Status;
}

LoRaWAN join after standby

I'm sending some information using LoRaWAN on a STM32WB and after that, I enter standby mode.
The problem is that after my standby, a new join is done.
I have heard that my join could be keep in memory using MIB functions but I don't manage to use them properly and continue to do a join do not make a join at all...
Does somebody know how to use them or a good tutorial somewhere? (I didn't find anything for the moment)
Here is what I am trying actually :
uint32_t last_time = 0;
int main(void)
{
/* USER CODE BEGIN 1 */
data_t data;
LoraFlagStatus join_status = LORA_RESET;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_I2C1_Init();
MX_LPTIM1_Init();
MX_LPUART1_UART_Init();
MX_RF_Init();
HW_RTC_Init();
MX_SPI1_Init();
MX_I2C3_Init();
MX_SPI2_Init();
/* USER CODE BEGIN 2 */
/* Reduce the System clock to below 2 MHz */
SystemClock_Decrease();
/* Set regulator voltage to scale 2 */
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2);
HAL_PWREx_EnableLowPowerRunMode();
float iaq;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_NETWORK_ACTIVATION;
LoRaMacMibGetRequestConfirm( &mibReq );
if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
{
lora_init();
join_status = lora_join();
}
while (1)
{
//sensor code and lora send
lora_update(); /* Must be called for the LoRa stack to work */
pres = false;
/* Enable and set RTC_WKUP_IRQ */
HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
/* Check if the system was resumed from StandBy mode */
/* Note: On STM32WB, both CPU1 and CPU2 must be in standby mode to set the entire system in standby mode */
if( (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)
&& (__HAL_PWR_GET_FLAG(PWR_FLAG_C2SB) != RESET)
)
{
/* Clear Standby flag */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_C2SB);
}
/* Insert 5 seconds delay */
HAL_Delay(5000);
/* Disable all used wakeup sources*/
HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle);
/* Clear all related wakeup flags */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
/* Re-enable wakeup source */
/* ## Setting the Wake up time ############################################*/
HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, 60, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);;
/* Specific procedure on STM32WB, in case of initial power-up and RF stack no started */
if( (LL_PWR_IsActiveFlag_C1SB() == 0)
|| (LL_PWR_IsActiveFlag_C2SB() == 0)
)
{
/* Set the lowest low-power mode for CPU2: shutdown mode */
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
}
/* Enter the Standby mode */
HAL_PWR_EnterSTANDBYMode();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
/**
* #brief System Clock Speed decrease
* The system Clock source is shifted from HSI to MSI
* while at the same time, MSI range is set to RCC_MSIRANGE_5
* to go down to 2MHz
* #param None
* #retval None
*/
void SystemClock_Decrease(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
/* Select MSI as system clock source */
/* Note: Keep AHB and APB prescaler settings from previous structure initialization */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* Disable PLL to reduce power consumption since MSI is used from that point */
/* Change MSI frequency */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
}
/* USER CODE END 4 */

f_mount() returns FA_DISK_ERR

I have made few changes in my source code after suggestion form everyone.For connecting FATFS API with SPI interface i have followed this code..
https://github.com/eziya/STM32_SPI_SDCARD/blob/master/Src/fatfs_sd.c
and changed my user_diskio.c accordingly.
After doing all those things then also my SD Card returns FA_DISK_ERROR.
I have changed SD Card slot as well as SD Card. But nothing Changed.
My user_diskio.c look like this:
#include <string.h>
#include "ff_gen_drv.h"
#include "fatfs_sd.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Disk status */
static volatile DSTATUS Stat = STA_NOINIT;
/* USER CODE END DECL */
/* Private function prototypes -----------------------------------------------*/
DSTATUS USER_initialize (BYTE pdrv);
DSTATUS USER_status (BYTE pdrv);
DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1
DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff);
#endif /* _USE_IOCTL == 1 */
Diskio_drvTypeDef USER_Driver =
{
USER_initialize,
USER_status,
USER_read,
#if _USE_WRITE
USER_write,
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
USER_ioctl,
#endif /* _USE_IOCTL == 1 */
};
/* Private functions ---------------------------------------------------------*/
/**
* #brief Initializes a Drive
* #param pdrv: Physical drive number (0..)
* #retval DSTATUS: Operation status
*/
DSTATUS USER_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
/* USER CODE BEGIN INIT */
return SD_disk_initialize(pdrv);
/* USER CODE END INIT */
}
/**
* #brief Gets Disk Status
* #param pdrv: Physical drive number (0..)
* #retval DSTATUS: Operation status
*/
DSTATUS USER_status (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
/* USER CODE BEGIN STATUS */
return SD_disk_status(pdrv);
/* USER CODE END STATUS */
}
/**
* #brief Reads Sector(s)
* #param pdrv: Physical drive number (0..)
* #param *buff: Data buffer to store read data
* #param sector: Sector address (LBA)
* #param count: Number of sectors to read (1..128)
* #retval DRESULT: Operation result
*/
DRESULT USER_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
/* USER CODE BEGIN READ */
return SD_disk_read(pdrv, buff, sector, count);
/* USER CODE END READ */
}
/**
* #brief Writes Sector(s)
* #param pdrv: Physical drive number (0..)
* #param *buff: Data to be written
* #param sector: Sector address (LBA)
* #param count: Number of sectors to write (1..128)
* #retval DRESULT: Operation result
*/
#if _USE_WRITE == 1
DRESULT USER_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
/* USER CODE BEGIN WRITE */
/* USER CODE HERE */
return SD_disk_write(pdrv, buff, sector, count);
/* USER CODE END WRITE */
}
#endif /* _USE_WRITE == 1 */
/**
* #brief I/O control operation
* #param pdrv: Physical drive number (0..)
* #param cmd: Control code
* #param *buff: Buffer to send/receive control data
* #retval DRESULT: Operation result
*/
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
/* USER CODE BEGIN IOCTL */
return SD_disk_ioctl(pdrv, cmd, buff);
/* USER CODE END IOCTL */
}
#endif /* _USE_IOCTL == 1 */
and fatfs_sd.c looks like this:
GO TO THE ABOVE GITHUB LINK
Have no idea where i am going wrong.
Anything on this topic will be helpful.
Thanks in advance.
I've written my own driver using an stm32f7 chip for FatFS before and think I might know what's going on. My guess is that you likely forgot to attach implementations for the disk_write and disk_read functions in diskio.h. Without doing that, the FatFS library has no clue on how to actually interface with the SD card.
You could check out the FatFS documentation/manual as a general resource: here
Pay very close attention to the "Required Functions" section in this app note: here
An example project like yours but for STM32F4: here

Why does trace_printf("%f",x); trigger a hard fault on an STM32 MCU?

I'm using an STM32 F413ZH microcontroller with HAL libraries (mainly written to be used with C, but can also be used with C++) in Eclipse. Actually I managed to completely configure Eclipse including semihosting and debug mode (OpenOCD), the basic project files and also I managed to manually adapt the basic project files given by STM32CubeMX to work with C++. So... now I can use HAL libraries in a C++ Eclipse environment and test my code via OpenOCD and trace_printf trace_puts using semihosting.
Now, again, after struggling too much setting up an STM32 environment, I find myself stuck, but this time is different.
These last seven days I have been looking for a solution to my problem, and I have tried many suggestions from similar issues online, but none of them has solved my problem.
Well, I'm facing a hard fault when using trace_printf() in semihosting while debugging. If I use this function to print an integer (%d) via semihosting everything is okay, and I can read the printed value in the OpenOCD console, but when I tried to print a value with the %f formatter the supposedly printed data wasn't being shown in the OpenOCD console.
Then I read that in order to enable the printing of floating point values I needed to add -u _printf_float to the linker flags, so after adding the flag I tried to trace_printf() a floating value, an integer value, or whatever data type, but all of them using the %f formatter, but I keep getting a hard fault using %f in trace_printf().
[HardFault]
Stack frame:
R0 = 00666E69
R1 = 2004FE78
R2 = 2004FF00
R3 = 00666E69
R12 = F642D800
LR = 08005DE7
PC = 08006586
PSR = 01000000
FSR/FAR:
CFSR = 00008200
HFSR = 40000000
DFSR = 0000000A
AFSR = 00000000
BFAR = 00666E69
Misc
LR/EXC_RETURN= FFFFFFF9
By debugging step by step, the hard fault handler is triggered after this function is called: vsnprintf()
I'm using these linker flags:
-T mem.ld -T libs.ld -T sections.ld -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"ThreePhaseSignals.map" --specs=nano.specs -u _printf_float
My project settings are:
Project toolchains
Target processor settings
C++ preprocessor
Linker settings and flags
My _sbrk.c is:
_sbrk.c
My linker files are:
mem.ld is:
mem.ld
And sections.ld is:
/*
* Default linker script for Cortex-M (it includes specifics for
STM32F[34]xx).
*
* To make use of the multi-region initialisations, define
* OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS for the _startup.c file.
*/
/*
* The '__stack' definition is required by crt0, do not remove it.
*/
__stack = ORIGIN(RAM) + LENGTH(RAM);
_estack = __stack; /* STM specific definition */
/*
* Default stack sizes.
* These are used by the startup in order to allocate stacks
* for the different modes.
*/
__Main_Stack_Size = 1024;
PROVIDE ( _Main_Stack_Size = __Main_Stack_Size );
__Main_Stack_Limit = __stack - __Main_Stack_Size;
/* "PROVIDE" allows to easily override these values from an
* object file or the command line. */
PROVIDE(_Main_Stack_Limit = __Main_Stack_Limit);
/*
* There will be a link error if there is not this amount of
* RAM free at the end.
*/
_Minimum_Stack_Size = 256;
/*
* Default heap definitions.
* The heap start immediately after the last statically allocated
* .sbss/.noinit section, and extends up to the main stack limit.
*/
PROVIDE(_Heap_Begin = _end_noinit);
PROVIDE(_Heap_Limit = __stack - __Main_Stack_Size);
/*
* The entry point is informative, for debuggers and simulators,
* since the Cortex-M vector points to it anyway.
*/
ENTRY(_start)
/* Sections Definitions */
SECTIONS
{
/*
* For Cortex-M devices, the beginning of the startup code is stored in
* the .isr_vector section, which goes to FLASH.
*/
.isr_vector : ALIGN(4)
{
FILL(0xFF)
__vectors_start = ABSOLUTE(.);
__vectors_start__ = ABSOLUTE(.); /* STM specific definition */
KEEP(*(.isr_vector)) /* Interrupt vectors */
KEEP(*(.cfmconfig)) /* Freescale configuration words */
/*
* This section is here for convenience, to store the
* startup code at the beginning of the flash area, hoping that
* this will increase the readability of the listing.
*/
*(.after_vectors .after_vectors.*) /* Startup code and ISR */
} >FLASH
.inits : ALIGN(4)
{
/*
* Memory regions initialisation arrays.
*
* Thee are two kinds of arrays for each RAM region, one for
* data and one for bss. Each is iterrated at startup and the
* region initialisation is performed.
*
* The data array includes:
* - from (LOADADDR())
* - region_begin (ADDR())
* - region_end (ADDR()+SIZEOF())
*
* The bss array includes:
* - region_begin (ADDR())
* - region_end (ADDR()+SIZEOF())
*
* WARNING: It is mandatory that the regions are word aligned,
* since the initialisation code works only on words.
*/
__data_regions_array_start = .;
LONG(LOADADDR(.data));
LONG(ADDR(.data));
LONG(ADDR(.data)+SIZEOF(.data));
LONG(LOADADDR(.data_CCMRAM));
LONG(ADDR(.data_CCMRAM));
LONG(ADDR(.data_CCMRAM)+SIZEOF(.data_CCMRAM));
__data_regions_array_end = .;
__bss_regions_array_start = .;
LONG(ADDR(.bss));
LONG(ADDR(.bss)+SIZEOF(.bss));
LONG(ADDR(.bss_CCMRAM));
LONG(ADDR(.bss_CCMRAM)+SIZEOF(.bss_CCMRAM));
__bss_regions_array_end = .;
/* End of memory regions initialisation arrays. */
/*
* These are the old initialisation sections, intended to contain
* naked code, with the prologue/epilogue added by crti.o/crtn.o
* when linking with startup files. The standalone startup code
* currently does not run these, better use the init arrays below.
*/
KEEP(*(.init))
KEEP(*(.fini))
. = ALIGN(4);
/*
* The preinit code, i.e. an array of pointers to initialisation
* functions to be performed before constructors.
*/
PROVIDE_HIDDEN (__preinit_array_start = .);
/*
* Used to run the SystemInit() before anything else.
*/
KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))
/*
* Used for other platform inits.
*/
KEEP(*(.preinit_array_platform .preinit_array_platform.*))
/*
* The application inits. If you need to enforce some order in
* execution, create new sections, as before.
*/
KEEP(*(.preinit_array .preinit_array.*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/*
* The init code, i.e. an array of pointers to static constructors.
*/
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/*
* The fini code, i.e. an array of pointers to static destructors.
*/
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/*
* For some STRx devices, the beginning of the startup code
* is stored in the .flashtext section, which goes to FLASH.
*/
.flashtext : ALIGN(4)
{
*(.flashtext .flashtext.*) /* Startup code */
} >FLASH
/*
* The program code is stored in the .text section,
* which goes to FLASH.
*/
.text : ALIGN(4)
{
*(.text .text.*) /* All remaining code */
/* Read-only data (constants) */
*(.rodata .rodata.* .constdata .constdata.*)
*(vtable) /* C++ virtual tables */
KEEP(*(.eh_frame*))
/*
* Stub sections generated by the linker, to glue together
* ARM and Thumb code. .glue_7 is used for ARM code calling
* Thumb code, and .glue_7t is used for Thumb code calling
* ARM code. Apparently always generated by the linker, for some
* architectures, so better leave them here.
*/
*(.glue_7)
*(.glue_7t)
} >FLASH
/* ARM magic sections */
.ARM.extab : ALIGN(4)
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
. = ALIGN(4);
__exidx_start = .;
.ARM.exidx : ALIGN(4)
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
. = ALIGN(4);
_etext = .;
__etext = .;
/* MEMORY_ARRAY */
/*
.ROarraySection :
{
*(.ROarraySection .ROarraySection.*)
} >MEMORY_ARRAY
*/
/*
* The secondary initialised data section.
*/
.data_CCMRAM : ALIGN(4)
{
FILL(0xFF)
*(.data.CCMRAM .data.CCMRAM.*)
. = ALIGN(4) ;
} > CCMRAM AT>FLASH
/*
* This address is used by the startup code to
* initialise the .data section.
*/
_sidata = LOADADDR(.data);
/*
* The initialised data section.
*
* The program executes knowing that the data is in the RAM
* but the loader puts the initial values in the FLASH (inidata).
* It is one task of the startup to copy the initial values from
* FLASH to RAM.
*/
.data : ALIGN(4)
{
FILL(0xFF)
/* This is used by the startup code to initialise the .data section */
_sdata = . ; /* STM specific definition */
__data_start__ = . ;
*(.data_begin .data_begin.*)
*(.data .data.*)
*(.data_end .data_end.*)
. = ALIGN(4);
/* This is used by the startup code to initialise the .data section */
_edata = . ; /* STM specific definition */
__data_end__ = . ;
} >RAM AT>FLASH
/*
* The uninitialised data sections. NOLOAD is used to avoid
* the "section `.bss' type changed to PROGBITS" warning
*/
/* The secondary uninitialised data section. */
.bss_CCMRAM (NOLOAD) : ALIGN(4)
{
*(.bss.CCMRAM .bss.CCMRAM.*)
} > CCMRAM
/* The primary uninitialised data section. */
.bss (NOLOAD) : ALIGN(4)
{
__bss_start__ = .; /* Standard newlib definition */
_sbss = .; /* STM specific definition */
*(.bss_begin .bss_begin.*)
*(.bss .bss.*)
*(COMMON)
*(.bss_end .bss_end.*)
. = ALIGN(4);
__bss_end__ = .; /* Standard newlib definition */
_ebss = . ; /* STM specific definition */
} >RAM
.noinit_CCMRAM (NOLOAD) : ALIGN(4)
{
*(.noinit.CCMRAM .noinit.CCMRAM.*)
} > CCMRAM
.noinit (NOLOAD) : ALIGN(4)
{
_noinit = .;
*(.noinit .noinit.*)
. = ALIGN(4) ;
_end_noinit = .;
} > RAM
/* Mandatory to be word aligned, _sbrk assumes this */
PROVIDE (end = _end_noinit); /* Was _ebss */
PROVIDE (_end = _end_noinit);
PROVIDE (__end = _end_noinit);
PROVIDE (__end__ = _end_noinit);
/*
* Used for validation only, do not allocate anything here!
*
* This is just to check that there is enough RAM left for the Main
* stack. It should generate an error if it's full.
*/
._check_stack : ALIGN(4)
{
. = . + _Minimum_Stack_Size;
} >RAM
/*
* The FLASH Bank1.
* The C or assembly source must explicitly place the code
* or data there using the "section" attribute.
*/
.b1text : ALIGN(4)
{
*(.b1text) /* Remaining code */
*(.b1rodata) /* Read-only data (constants) */
*(.b1rodata.*)
} >FLASHB1
/*
* The EXTMEM.
* The C or assembly source must explicitly place the code or data there
* using the "section" attribute.
*/
/* EXTMEM Bank0 */
.eb0text : ALIGN(4)
{
*(.eb0text) /* Remaining code */
*(.eb0rodata) /* Read-only data (constants) */
*(.eb0rodata.*)
} >EXTMEMB0
/* EXTMEM Bank1 */
.eb1text : ALIGN(4)
{
*(.eb1text) /* Remaining code */
*(.eb1rodata) /* Read-only data (constants) */
*(.eb1rodata.*)
} >EXTMEMB1
/* EXTMEM Bank2 */
.eb2text : ALIGN(4)
{
*(.eb2text) /* Remaining code */
*(.eb2rodata) /* read-only data (constants) */
*(.eb2rodata.*)
} >EXTMEMB2
/* EXTMEM Bank0 */
.eb3text : ALIGN(4)
{
*(.eb3text) /* Remaining code */
*(.eb3rodata) /* Read-only data (constants) */
*(.eb3rodata.*)
} >EXTMEMB3
/* After that there are only debugging sections. */
/* This can remove the debugging information from the standard libraries */
/*
DISCARD :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
*/
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/*
* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0.
*/
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}
On the Internet many people says that this is because printing floats consumes a lot of memory and probable the microcontroller is crashing due to memory overflow, so many suggestions aim to modify the linker script where stack and heap assignations are made, and some others say that this hard fault is related to_sbrk.c in newlib.
I tried to adapt these solutions to my particular case, but till now my problem still is not solved. I don't know if I'm badly implementing the suggestions or simply my problem is different.
How can I fix this problem?
Solved. Follow the following video and if it doesn't work follow the full series of videos.
STM32 with Eclipse, GNU ARM and J-Link. Part 4 - Minimal CMSIS Project - ITM Printf Debugging

New Emacs primitive does not show up

I wrote a new Emacs primitive (macroexpand-once) and recompiled Emacs
Now (macroexpand-once) fails with "Symbol's function definition is void".
What do I do about this?
UPDATE: Here is the code:
DEFUN ("macroexpand-once", Fmacroexpand_once, Smacroexpand_once, 1, 2, 0,
doc: /* Return result of expanding macros at top level of FORM.
If FORM is not a macro call, it is returned unchanged.
Otherwise, the macro is expanded and the expansion is returned.
The second optional arg ENVIRONMENT specifies an environment of macro
definitions to shadow the loaded ones for use in file byte-compilation. */)
(Lisp_Object form, Lisp_Object environment)
{
/* With cleanups from Hallvard Furuseth. */
register Lisp_Object expander, sym, def, tem;
do
{
/* Come back here each time we expand a macro call,
in case it expands into another macro call. */
if (!CONSP (form))
break;
/* Set SYM, give DEF and TEM right values in case SYM is not a symbol. */
def = sym = XCAR (form);
tem = Qnil;
/* Trace symbols aliases to other symbols
until we get a symbol that is not an alias. */
while (SYMBOLP (def))
{
QUIT;
sym = def;
tem = Fassq (sym, environment);
if (NILP (tem))
{
def = XSYMBOL (sym)->function;
if (!EQ (def, Qunbound))
continue;
}
break;
}
/* Right now TEM is the result from SYM in ENVIRONMENT,
and if TEM is nil then DEF is SYM's function definition. */
if (NILP (tem))
{
/* SYM is not mentioned in ENVIRONMENT.
Look at its function definition. */
struct gcpro gcpro1;
GCPRO1 (form);
def = Fautoload_do_load (def, sym, Qmacro);
UNGCPRO;
if (EQ (def, Qunbound) || !CONSP (def))
/* Not defined or definition not suitable. */
break;
if (!EQ (XCAR (def), Qmacro))
break;
else expander = XCDR (def);
}
else
{
expander = XCDR (tem);
if (NILP (expander))
break;
}
{
Lisp_Object newform = apply1 (expander, XCDR (form));
if (EQ (form, newform))
break;
else
form = newform;
}
} while (0);
return form;
}
It is just the code of macroexpand, but with do-while(0) instead of while(1).
You need to call defsubr. Do a search for Smacroexpand to see what I mean.