I am working on an embedded C project in Keil µVision. Part of the project is to make the uC detect and operate as a USB flash drive. I am using a STM32L072 that is connected to external SPI Flash via SPI2 (P/N: SST26VF016B). I can read/write/erase/ the SST26V flash chip with no issues and I can communicate over USB with no problems. If I plug the device into a Windows based computer via USB it detects as a flash drive with the appropriate capacity (in this case 64KB[see NOTE 1 below]). Windows then will prompt me to format the drive. When I try to format the drive with the following parameters:
(Capacity: 64KB, File System: FAT (Default), Allocation unit size: 512 bytes, Quick Format: checked)
Windows will issue a bunch of reads and writes and eventually fail with an error messages that reads "Windows was unable to complete the format".
I seem to be having a problem bridging the gap between USB and SPI. I modified the usbd_storage_if.c following tutorials like this one. I only modified a few lines of code shown below:
#define STORAGE_LUN_NBR 1 // Logical Unit Number
//#define STORAGE_BLK_NBR 3840 // Use all memory in the SST26V
#define STORAGE_BLK_NBR 80 // Use ONLY the first 64kB of flash for testing.
#define STORAGE_BLK_SIZ 0x200
#define SST26V_MEMORY_OFFSET 0x10000 // This is the starting address of the SST26V's memory
....
/**
* #brief .
* #param lun: .
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
printf("\r\nR%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
_SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, buf);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* #brief .
* #param lun: .
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
// incoming USB data packets are 512Bytes
printf("\r\nW%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
_SPI_FLASH_WritePage(256, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), buf); // As per SST26V datasheet, can only write 256B at a time
_SPI_FLASH_WritePage(256, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET + 256), buf+256);
return (USBD_OK);
/* USER CODE END 7 */
}
If I attempt to format the drive and then dump the 64KB flash contents over UART I get the following:
:00010000|2000000000000000200020000000000000000000000000000000000000000000
:00010020|0000000000002000000020000000000000002000200000000000200020002000
:00010040|0800100010001000000000001000000010000000000000000000000010000000
:00010060|0400040004000000040004000400800000000400000010000000000000001000
:00010080|0000010000000000010000008100000000000000010000000000010001000100
:000100A0|0100010001000000000001000000000000000100000010000000000000001000
:000100C0|0000020000008200000082008200000002000000020000000000000000000000
:000100E0|0200000000000200000002000000000000000200000000001000100010000000
:00010100|0000000000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00010C00|F8FFFF0000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00010E00|F8FFFF0000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00015000|FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
... (all FF's in between these regions)
:0001FE00|0000000000000000000000000000000000000000000000000000000000000000
:0001FE20|0000000000000000000000000000000000000000000000000000000000000000
:0001FE40|0000000000000000000000000000000000000000000000000000000000000000
:0001FE60|0000000000000000000000000000000000000000000000000000000000000000
:0001FE80|0000000000000000000000000000000000000000000000000000000000000000
:0001FEA0|0000000000000000000000000000000000000000000000000000000000000000
:0001FEC0|0000000000000000000000000000000000000000000000000000000000000000
:0001FEE0|0000000000000000000000000000000000000000000000000000000000000000
:0001FF00|0000000000000000000000000000000000000000000000000000000000000000
:0001FF20|0000000000000000000000000000000000000000000000000000000000000000
:0001FF40|0000000000000000000000000000000000000000000000000000000000000000
:0001FF60|0000000000000000000000000000000000000000000000000000000000000000
:0001FF80|0000000000000000000000000000000000000000000000000000000000000000
:0001FFA0|0000000000000000000000000000000000000000000000000000000000000000
:0001FFC0|0000000000000000000000000000000000000000000000000000000000000000
:0001FFE0|0000000000000000000000000000000000000000000000000000000000000000
Any ideas what I might be missing? I also find it slightly odd that the first 20,448 (0x4FE0) bytes is primarily zeros. This memory chip is NAND flash and so I would except all unused space to be FF's. Which makes me think; any space being written to must be erased before being written to (unless the space is already all FF's), but the smallest size I can erase on the SST26V is a sector (4 Kbyte). Does this mean the my Allocation unit size should be 4096 bytes, not 512 bytes?
NOTES
1. I'm using the first 64KB of flash to make debugging easier. Takes too long to print out entire 2MB (8Mbit) of flash over UART.
UPDATE # 1
I think I may have found the problem, but have yet to solve it. When I review all of the read write addresses that are printed out over UART I find multiple instances of Windows writing 512 bytes to address 0x00010000. Seeing as this is NAND flash it must be erased before it can be written to again, but because the smallest amount of memory that can be erased is 4kB I suppose this means that I will have to copy the 4kB flash sector to the STM32's RAM, modify the first 512 bytes, erase the 4kB flash sector, then write what I have in RAM back to the 4kB flash sector. Does that sound correct? Seems inefficient.
UPDATE # 2
I confirmed that my suspicions in UPDATE 1 were correct. I tried using only the first 512 bytes of each sector and it works, but as a result only has 1/8 of the capacity. More updates to follow.
I was able to solve my problem. I was on the correct path in UPDATES 1 & 2.
I was able to use the entire 2MB region of the external flash by creating some new functions that deal with flash memory from a sector perspective and a buffer in RAM that is the size of a sector (4KB). See code below:
/**
* #brief .
* #param lun: .
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
if((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET) == 0x00010000)
printf("\r\nR %d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
_SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, buf);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* #brief .
* #param lun: .
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
uint8_t IsBlockEmptyFlag = 0;
uint8_t temp = 0xFF;
uint16_t sector_number = 0;
uint8_t block_number = 0;
/* USER CODE BEGIN 7 */
printf("\r\nW%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + bytes
// First, check if block that we want to write to is empty (All bytes are 0xFF)
_SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, RAMbuffer);
for(uint16_t i = 0; i<512; i++)
temp &= RAMbuffer[i];
if(temp == 0xFF) // then all bytes must be 0xFF and the block is ready to be writen to.
IsBlockEmptyFlag = 1;
if(IsBlockEmptyFlag) // if the block is empty already, have at it, write away
{
_SPI_FLASH_WritePage(blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), buf);
}
else // if it's not empty
{
printf("\r\nt=%02X", temp);
// Find the sector number that this block is in
sector_number = blk_addr/8;
// Save the entire flash sector to RAM
_SPI_FLASH_ReadSector(sector_number, RAMbuffer);
// Erase the sector flash sector
SST26V_FLASH_EraseSectorN(sector_number);
// compute the block number of the corresponding sector
block_number = blk_addr % 8;
// create a pointer to the RAM buffer
uint8_t *p_RAM_buffer;
p_RAM_buffer = RAMbuffer;
// Modify the RAM buffer's appropriate block
memcpy(p_RAM_buffer + (512*block_number), buf, blk_len*STORAGE_BLK_SIZ);
// Write the buffer back into external flash
_SPI_FLASH_WriteSector(sector_number, RAMbuffer);
}
return (USBD_OK);
/* USER CODE END 7 */
}
Related
I am using STM32L475 dev board and SIM7600 4g module. I have implemented MQTT communication in this project. I can successfully connect to MQTT broker and also able to receive the data. But the problem is size of data is large (240000 bytes ie 234.375KB).RAM available in this Dev board is 128 KiloBytes. I WANT TO STORE THIS DATA IN EXTERNAL FLASH MEMORY.
I am using UART with DMA. So whenever I get data on UART from SIM7600 module, MCU goes interrupt routine and there I can copy the content of rx_buffer into any other buffer for further processing.
I can see in debugger window, the "next_size" variable which counts the incoming data showing me size 244824 ie 240000 bytes plus the MQTT headers.
But when I call the functions of QSPI to store this data in External flash memory, MCU does not download the packets after first 512 bytes.MCU takes time(I assume) and It misses the other data. I can see "next_size" does not increase.
function in code is as below
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
if (huart->Instance == UART4) {
new_size = Size + prev_size;
prev_size = new_size;
/*
* BSP_QSPI_Write this function writes data to external flash
memory
* uint8_t BSP_QSPI_Write(uint8_t *pData, uint32_t WriteAddr,
uint32_t Size)
*/
memcpy((uint8_t*) copy_buf, (uint8_t*) rx_buf, Size);
if (BSP_QSPI_Write(copy_buf, (WRITE_READ_ADDR + next_address),Size) != QSPI_OK) {
printf("QSPI WRITE : FAILED.\n");
//printf("QSPI Test Aborted.\n");
}
else {
//printf("data written to flash\r\n");
next_address = next_address + Size;
}
/* start the DMA again */
HAL_UARTEx_ReceiveToIdle_DMA(&huart4, rx_buf, rx_buf_size);
__HAL_DMA_DISABLE_IT(&hdma_uart4_rx, DMA_IT_HT);
if (network_init_flag == 0) { //stops printing when large data
//starts downloading
printf("Response=%s \r\n", rx_buf);
}
}
}
I'm trying to configure and read data from a LIS2DE12 Acc using SPI Comm. The master of the SPI is an EM9304 uC. First, I'm trying to read the "WHO AM I" register, and compare with the ID provided in the datasheet of the LIS2DE12. The module does respond, but using the oscilloscope I've found out that it keeps sending it's ID through MISO at every transaction.
For example, if I write some bytes to LIS2DE12, while the MOSI is sending the byte, the MISO is sending the LIS2DE12 ID. If I try to read another register with a known value, It stills responds with the LIS2DE12 ID and does not send the register content.
I am new to SPI Comm, but I dont think that its a normal behavior.
This is the struct used to pass the bytes.
typedef struct{
struct{
uint8_t address : 6; //6bit address
uint8_t ms : 1; //If 0, keep the address unchanged, else, it increments the address in case of writing/reading multiple bytes
uint8_t mode : 1; //Read/Write
}control;
uint8_t data; //8bit data
}SPIM_Transaction_t;
Some prints of what is going on.
Clock and MOSI signals
Clock and MISO signals
In the MOSI image, the first 2 Bytes represents a write attempt.
First Byte:
00100011 byte:
0 - Write/ 0 - Dont increment address/ 100011 - 0x0F - The register address
Second Byte:
00110000 byte: 0x30 - The value I want to load in the register.
The next 2 Bytes represents an attempt to read this same register: 10100011
1 - Read 0 - Dont increment address 100011 - (0x23) - Register Address
And 8bits of zero, expecting the sensor to answer with an 8bit data.
In the Clock and MISO image, we can see that the sensor answers with 0x33 whenever there's a clock signal. Because of the symmetry it could be just a random or an error signal.
I am using the correct polarity and phase, other combinations doesnt get any result. The slave CS is grounded to be always activated.
I am using an SPI library and using this function to write bytes:
/**
* #brief Performs one or more write operations.
*
* This is a non-blocking operation, the input buffer cannot be modified until
* the transaction is complete.
*
* #note If the buffer is on the stack, you must ensure that the transaction
* completes before the function exits.
*
* #param chipSelectGpio Number of the GPIO to use for the chip select.
* #param[in] pWriteBuffer An array of data to write to the device.
* #param bytes The number of entries in the source array.
* #param[in] callbackFunction The function to call after the transaction is
* complete, the return status is passed as an argument.
* #param[in] pUserData The data to pass to the callback function.
* #param frequency Maximum clock frequency to send the transaction at or 0 to
* not change the clock frequency (previous frequency is used).
* #returns true if the transaction was scheduled, false otherwise.
*/
//lint -function( fopen(1), SPIM_WriteBytes(2) ) // arg cannot be null
bool SPIM_WriteBytes(uint8_t chipSelectGpio, const uint8_t *pWriteBuffer,
uint8_t bytes, Driver_Callback_t callbackFunction, void *pUserData,
uint32_t frequency);
uint32_t PAGEError = 0;
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS ;
EraseInitStruct.Sector = FLASH_SECTOR_0;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, 0x08000000, counter)
HAL_FLASH_Lock();
counter2 = *(__IO uint32_t *)0x08000000;
counter3 = *(__IO uint32_t *)0x08000001;
counter4 = *(__IO uint32_t *)0x08000002;
sprintf(buf, "%d", counter2); //gets send to the OLED with I2C
sprintf(buf2, "%d", counter3);
sprintf(buf3, "%d", counter4);
I want to write the variable counter to the flash and then read it as counter2.
The first flash sector starts at 0x08000000.
counter2, 3 and 4 are display trough an OLED screen.
Displaying counter2 works and shows me the value of counter-1, but it works only once. If I write again to the flash nothing seems to happen.
counter3 and counter4 don't work at all.
Output on the OLED when counter=0x00000008 after I have erased the flash but not written anything:
counter2: 536873624
counter3: -652214262
counter4: 31006720
And after writting and ressetting:
counter2: 8
counter3: -654311424
counter4: 30998528
What is going on here? Can someone tell me why all variables change?
Do I have to configure the linker?
I will treat you now as begineer, but will say sorry if you are not.
STM32 devices have flash on 0x08000000 and by erasing this sector, you did failure on startup because you erased actual part from where CPU loads instructions.
When you tried to erase sectors, you did not specify how many sectors to erase.
Reading of counters is wrong. Since you have uint32_t variable, you have to do 4-bytes between readings, something like:
counter2 = *(__IO uint32_t *)0x08000000;
counter3 = *(__IO uint32_t *)0x08000004;
counter4 = *(__IO uint32_t *)0x08000008;
Correct erasing is shown below.
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FLASH_SECTOR_0; //Specify sector number
EraseInitStruct.NbSectors = 1; //This is also important!
if(HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
//Erase error!
}
So, find out how long is your program and do your operations in sector after your program.
You can find example for EraseProgram in STM32CubeF4 package.
STM32Cube_FW_F4_V1.16.0\Projects\STM324x9I_EVAL\Examples\FLASH\FLASH_EraseProgram\Src\main.c
Concept will work also on your nucleo, just make sure you set correct address for flash erasing.
Thanks to #phoenix!
In Stm32CubF3 reference erasing flash works as follows:
There is to mention how a memory page address is looking:
/* Base address of the Flash sectors */
#define ADDR_FLASH_PAGE_0 ((uint32_t)0x08000000) /* Base # of Page 0, 2 Kbytes */
#define ADDR_FLASH_PAGE_1 ((uint32_t)0x08000800) /* Base # of Page 1, 2 Kbytes */
#define ADDR_FLASH_PAGE_2 ((uint32_t)0x08001000) /* Base # of Page 2, 2 Kbytes */
#define ADDR_FLASH_PAGE_3 ((uint32_t)0x08001800) /* Base # of Page 3, 2 Kbytes */
#define ADDR_FLASH_PAGE_4 ((uint32_t)0x08002000) /* Base # of Page 4, 2 Kbytes */
#define ADDR_FLASH_PAGE_5 ((uint32_t)0x08002800) /* Base # of Page 5, 2 Kbytes */
#define ADDR_FLASH_PAGE_6 ((uint32_t)0x08003000) /* Base # of Page 6, 2 Kbytes */
So your minimal code looks as follows:
I want to delete my application # 0x08003000 --> FLASH_PAGE_6. The erasing is done 2kB wise:
/* EEPROM start address in Flash */
#define EEPROM_START_ADDRESS ((uint32_t)ADDR_FLASH_PAGE_32) /* 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 PAGE0_ID ADDR_FLASH_PAGE_32
/* Clear flash flags */
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGERR);
uint32_t *flash_ptr = 0x8003000;
uint32_t page_error = 0;
HAL_StatusTypeDef flashstatus;
FLASH_EraseInitTypeDef s_eraseinit;
/* Fill EraseInit structure*/
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = 1; // seems to be 1 !!!!
/* I want to delete 54kB in my flash --> 52kB / 2kB (per erase) = 26 iterations
After erasing one page, increment page by 0x800 = 2048 byte = 2kB = pagesize */
for(int pageCount = 0; pageCount < 26; pageCount++){
s_eraseinit.PageAddress = ADDR_FLASH_PAGE_6 + pageCount * 0x800;
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
}
The best way is to create the new segment of flash in the linkescriptr and place the data there. It is the safest.
If do not know linker scripts create a table of the one segment size, and place it at the end of the flash using your compiler directives.
If you do not know both I suggest a ready made STM eeprom emulation example from the Cube
Today I'm trying to convert this library: Arduino library for ClosedCube_HDC1080 Humidity and Temperature sensor to use it with an ATTiny841 ATTiny841 datasheet, to do it I'm going to use the Fleury's Library to use the ATTiny841 as Master and the HDC1080 as Slave.
My problem is that I have some issues to convert from the C++ language that is used in the HDC1080 library for Arduino to the ATTiny, which use C language, for that I would show you header files to explain myself.
HDC1080_Registers;
class ClosedCube_HDC1080 {
public:
ClosedCube_HDC1080();
void begin(uint8_t address);
uint16_t readManufacturerId(); // 0x5449 ID of Texas Instruments
uint16_t readDeviceId(); // 0x1050 ID of the device
HDC1080_Registers readRegister();
void writeRegister(HDC1080_Registers reg);
void heatUp(uint8_t seconds);
float readTemperature();
float readHumidity();
float readT(); // short-cut for readTemperature
float readH(); // short-cut for readHumidity
private:
uint8_t _address;
uint16_t readData(uint8_t pointer);
};
#endif
This is from the header (.h) file of HDC1080 sensor, I read that class function is not available in C language, so I decide to use struct function, which I saw that is available in C language, but in examples that I saw on Internet, they only use struct function to declare variables, and functions not like:
ClosedCube_HDC1080();
void begin(uint8_t address);
HDC1080_Registers readRegister();
void writeRegister(HDC1080_Registers reg);
void heatUp(uint8_t seconds);
They are define it outside of the struct function, so I get confused with those void's which are inside of the class function, this is reason why I looking for some help. I just need to know:
How to declare those functions to work with the struct
Is going to be much easier to define them later in the C (.c) file?
Thanks for your time and your patience, is my first time converting from one language to another.
Because the only internal state in that class is a single uint8_t, and this code is run on a microcontroller, it is much better to just supply that address as a parameter to each function.
First, note that my suggestions below are derivative of the ClosedCube HDC1080 Arduino library, and therefore licensed under the same license:
/*
Arduino Library for Texas Instruments HDC1080 Digital Humidity and Temperature Sensor
Originally written by AA for ClosedCube; this suggested conversion by Nominal Animal
---
The MIT License (MIT)
Copyright (c) 2016-2017 ClosedCube Limited
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
ATtinys are small 8-bit microcontrollers, so it's best to avoid using the float type. Instead, I suggest you use units of 1/1000 degrees Celsius for temperature (25000 referring to 25 degrees Celsius), and 1/100000 for humidity (50000 referring to 50% of relative humidity).
The interface to the adapted library can be quite simple:
void HDC1080_begin(const uint8_t address);
void HDC1080_heater(const uint8_t address, const uint8_t seconds);
uint16_t HDC1080_manufacturer(const uint8_t address);
uint16_t HDC1080_device_id(const uint8_t address);
int32_t HDC1080_temperature(const uint8_t address);
uint32_t HDC1080_humidity(const uint8_t address);
If we assume we keep temperature and humidity precision at 14 bits (configured by HDC1080_begin(), we don't need the user to set or read the configuration register.
The example code shows that HDC1080_manufacturer() should return 0x5449, and HDC1080_device_id() should return 0x1050.
Since we don't know what kind of interface the "Fleury's Library" has, I shall show the implementation of the above functions with comments (starting with /* I2C:) instead of actual library calls.
The static ones are internal functions only used by the abovementioned functions, not "user" code.
#define HDC1080_TEMPERATURE ((uint8_t)0x00)
#define HDC1080_HUMIDITY ((uint8_t)0x01)
#define HDC1080_CONFIGURATION ((uint8_t)0x02)
#define HDC1080_SERIAL_ID_FIRST ((uint8_t)0xFB)
#define HDC1080_SERIAL_ID_MID ((uint8_t)0xFC)
#define HDC1080_SERIAL_ID_LAST ((uint8_t)0xFD)
#define HDC1080_MANUFACTURER_ID ((uint8_t)0xFE)
#define HDC1080_DEVICE_ID ((uint8_t)0xFF)
/* Bits 15..8 of the HDC1080 configuration.
Heater disabled, 14 bit precision for
both temperature and relative humidity.
See page 15 of
http://www.ti.com/lit/ds/symlink/hdc1080.pdf
for other possibilities.
*/
#define HDC1080_CONFIG_HI ((uint8_t)0)
static uint16_t HDC1080_read(const uint8_t address, const uint8_t item)
{
uint8_t hi, lo;
/* I2C: Prepare to send to i2c address 'address'. */
/* I2C: Send 8 bits 'item'. */
/* I2C: End transmission. */
/* Delay for 9 ms (0.009 seconds). */
/* I2C: Prepare to read 2 bytes from i2c address 'address'. */
hi = /* I2C: Read byte. */
lo = /* I2C: Read byte. */
return (((uint16_t)hi) << 8) | lo;
}
void HDC1080_begin(const uint8_t address)
{
/* I2C: Prepare to send to i2c address 'address'. */
/* I2C: Send 8 bits: HDC1080_CONFIGURATION (=0x02). */
/* I2C: Send 8 bits: HDC1080_CONFIG_HI (=0x00). */
/* I2C: Send 8 bits: 0. */
/* I2C: End transmission. */
/* Delay for 10 ms = 0.01 seconds. */
}
void HDC1080_heater(const uint8_t address, const uint8_t seconds)
{
uint8_t s, i;
/* I2C: Prepare to send to i2c address 'address'. */
/* I2C: Send 8 bits: HDC1080_CONFIGURATION (=0x02). */
/* I2C: Send 8 bits: 48 (=0x30). */
/* I2C: Send 8 bits: 0. */
/* I2C: End transmission. */
/* Delay for 10 ms = 0.01 seconds. */
for (s = 0; s < seconds; s++) {
for (i = 0; i < 66; i++) {
/* I2C: Prepare to send to i2c address 'address'. */
/* I2C: Send 8 bits 'item'. */
/* I2C: End transmission. */
/* Delay for 20 ms (0.020 seconds). */
/* I2C: Prepare to read 4 bytes from i2c address 'address'. */
/* I2C: Read byte. (Ignore the value.) */
/* I2C: Read byte. (Ignore the value.) */
/* I2C: Read byte. (Ignore the value.) */
/* I2C: Read byte. (Ignore the value.) */
}
}
/* I2C: Prepare to send to i2c address 'address'. */
/* I2C: Send 8 bits: HDC1080_CONFIGURATION (=0x02). */
/* I2C: Send 8 bits: HDC1080_CONFIG_HI (=0x00). */
/* I2C: Send 8 bits: 0. */
/* I2C: End transmission. */
/* Delay for 10 ms = 0.01 seconds. */
}
uint16_t HDC1080_manufacturer(const uint8_t address)
{
return HDC1080_read(address, HDC1080_MANUFACTURER_ID);
}
uint16_t HDC1080_device_id(const uint8_t address)
{
return HDC1080_read(address, HDC1080_DEVICE_ID);
}
int32_t HDC1080_temperature(const uint8_t address)
{
uint16_t temp1 = HDC1080_read(address, HDC1080_TEMPERATURE) >> 2;
return (int_t)(((uint32_t)20625 * temp1 + (uint32_t)1024) >> 11) - (int32_t)40000;
}
uint32_t HDC1080_humidity(const uint8_t address)
{
uint16_t temp1 = HDC1080_read(address, HDC1080_HUMIDITY);
return ((uint32_t)3125 * temp1 + (uint32_t)1024) >> 11;
}
Note that the relative humidity range is 0 to 99998, i.e. 0%RH to 99.998% RH. This is not an error, and the formula is taken from the datasheet and losslessly scaled to the new range. Similarly, the possible temperature range is -40000 to +124989, corresponding to -40°C to +124.989°C, and this too is according to the TI datasheet, losslessly scaled to the new range. The + (uint32_t)1024 term in both ensures correct rounding (to nearest).
You do still need to implementing the /* I2C: and /* Delay comments using whatever library you have at hand.
I'm facing a problem with my erasing function.
I try to erase 15 sectors of my Flash in order to put a new binary file.
I don't understand why but my function freeze and i cannot erase all memory i need.
Here is my code if you want to give a try
/*
* bootloader.c
*
* Created on: 9 juin 2015
* Author: tgloaguen
*/
#include "usart.h"
#include "stm32l1xx_flash.h"
#define WRITE_START_ADDR 0x08000000
#define WRITE_END_ADDR 0x0800FFFF
#define FLASH_PAGE_SIZE ((uint16_t)0x100) //If a page is 256 bits
#define MY_BL_FUNCTIONS __attribute__((section(".bootsection")))
void BootLoader(void) MY_BL_FUNCTIONS;
FLASH_Status Flash_Write ( uint32_t StartAddress, uint8_t *p, uint32_t Size ) MY_BL_FUNCTIONS;
uint8_t Flash_Erase() MY_BL_FUNCTIONS;
void Receive_Data(char * buffer,int size)MY_BL_FUNCTIONS;
void Receive_Size(char * buffer, int *sizeData)MY_BL_FUNCTIONS;
void BootLoader(void) {
//clear all ITs
USART_ITConfig( USART1, USART_IT_RXNE, DISABLE );
//SendString("HELLO",USART2);
uint8_t status,i;
char buffer[33];
//en dur
uint16_t *adr = WRITE_START_ADDR;
uint16_t sizeBin = 51400,k = 0,k_hexa = 0x20;
SendString("BOOTLOADER",USART2);
Flash_Erase();
SendString("ERASEOK",USART2);
//if sizeBin ok
}
and the erase function
uint8_t Flash_Erase() {
uint32_t EraseCounter = 0x00, Address = 0x00;//Erase count, write address
uint32_t NbrOfPage = 0x00;//Recording to erase the pages
volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;/*FLASH complete erasure marks*/
/*Unlock FLASH*/
FLASH_Unlock();
/*Calculate the number of FLASH pages need to erase */
NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;
/* Remove all hang flags */
FLASH_ClearFlag ( FLASH_FLAG_EOP |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR |
FLASH_FLAG_SIZERR |
FLASH_FLAG_OPTVERR );
/* Erase the FLASH page*/
for(EraseCounter = 0; (EraseCounter <NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
{
SendString("ok |",USART2);
FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
}
FLASH_Lock ( );
return (uint8_t)FLASHStatus;
}
In your code you are tring to erase the whole flash, but you are executing your bootloader from flash from final sectors.
As reported by th REF man
During a write/erase operation to the NVM (except Half Page programming or Double-word
erase/write), any attempt to read the same bank of NVM stalls the bus.
Then you have to preserve the space of bootloader changing WRITE_END_ADDR define according to your memory map.
Example: if your bootloader is 4K long and belongs to the last sector (0x0801 F000 - 0x0801 FFFF) then WRITE_END_ADDR must be 0x0801 EFFF.
EDIT
As #Olaf wrote take care about your ISP (Initial Stack Pointer) and IPC (Initial Program Counter) that belong to first 8 bytes in your flash at address 0.