Forum: Mikrocontroller und Digitale Elektronik sprintf am STM32F072


von Manollo139 (Gast)


Lesenswert?

Hallo, ich sitze nun schon etwas länger an einem Problem und komme nicht 
weiter.
Mir gelingt es nicht den sprintf befehl auf meinem Cortex M0 zu 
verwenden.

#include <stdio.h>
...
...
while (1) {
    char buffer[10] = "hallo";
    uint8_t i=1;
    //sprintf(buffer, "Test %u",i);
    sprintf(buffer, "Test")
    HAL_UART_Transmit(&huart1, (char*) buffer, 100, 100);
    HAL_Delay(1000);
  }


Mit sprintf(buffer,"Test); funktioniert alles einwandfrei.
Sobald ich allerdings die erweiterten Funktionen von sprintf verwenden 
möchte geht da garnichts mehr.
Der µC lässt sich nichtmal mehr Debuggen.

Meine Entwicklungsumgebung ist Eclipse mit einem Makefile-Projekt. 
ST-Linker zum flashen. Habe auch schon viele dinge getestet. CAN-BUS, 
UART usw.. das funktioniert alles. Nur das einfache sprintf macht mich 
verrückt.

Auch snprintf habe ich versucht.

Diese Ausgabe bekomme ich von meiem Debugger wenn ich versuche zu 
debuggen.
Open On-Chip Debugger 0.8.0 (2014-04-28-08:39)
Licensed under GNU GPL v2
For bug reports, read
  http://openocd.sourceforge.net/doc/doxygen/bugs.html
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Started by GNU ARM Eclipse
Info : This adapter doesn't support configurable speed
Info : STLINK v2 JTAG v17 API v2 SWIM v0 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 2.925402
Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : accepting 'gdb' connection from 3333
Info : device id = 0x20016448
Info : flash size = 128kbytes
undefined debug reason 7 - target needs reset
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x08001c90 msp: 0x20003ffc
semihosting is enabled
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x08001c90 msp: 0x20003ffc, semihosting
Info : odd number of bytes to write, padding with 0xff
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20003ffc, semihosting
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x08001c90 msp: 0x20003ffc, semihosting
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x08001c90 msp: 0x20003ffc, semihosting
===== arm v7m registers
(0) r0 (/32): 0xFFFFFFFF
(1) r1 (/32): 0xFFFFFFFF
(2) r2 (/32): 0xFFFFFFFF
(3) r3 (/32): 0xFFFFFFFF
(4) r4 (/32): 0xFFFFFFFF
(5) r5 (/32): 0xFFFFFFFF
(6) r6 (/32): 0xFFFFFFFF
(7) r7 (/32): 0xFFFFFFFF
(8) r8 (/32): 0xFFFFFFFF
(9) r9 (/32): 0xFFFFFFFF
(10) r10 (/32): 0xFFFFFFFF
(11) r11 (/32): 0xFFFFFFFF
(12) r12 (/32): 0xFFFFFFFF
(13) sp (/32): 0x20003FFC
(14) lr (/32): 0xFFFFFFFF
(15) pc (/32): 0x08001C90
(16) xPSR (/32): 0xC1000000
(17) msp (/32): 0x20003FFC
(18) psp (/32): 0xFFFFFFFC
(19) primask (/1): 0x00
(20) basepri (/8): 0x00
(21) faultmask (/1): 0x00
(22) control (/2): 0x00
===== Cortex-M DWT registers
(23) dwt_ctrl (/32)
(24) dwt_cyccnt (/32)
(25) dwt_0_comp (/32)
(26) dwt_0_mask (/4)
(27) dwt_0_function (/32)
(28) dwt_1_comp (/32)
(29) dwt_1_mask (/4)
(30) dwt_1_function (/32)


Danke schonmal für eure Hilfe.

von Karl H. (kbuchegg)


Lesenswert?

Manollo139 schrieb:

>     char buffer[10] = "hallo";

Mach das Array mal größer.

9 druckbare Zeichen sind nicht sehr viel.
Durch "Test " gehen dir da schon mal 5 verloren und wenn dein sprintf 
für die Ausgabe der Zahl dann auch noch eine paar Zeichen verbrutzelt 
(Feldbreite etc.) dann bist du da schnell drüber.

von Matthias (Gast)


Lesenswert?

Hast du genug Heap reserviert? Üblicherweise verwenden 
*printf-Funktionen diesen zur Formatierung.

Wenn du unter Windows arbeitest könntest du überlegen den ARM Compiler 
zu verwenden: http://www2.keil.com/stmicroelectronics-stm32/mdk
Der macht das sicher so. Der Heap wird im dort meist im startup_*.s 
konfiguriert.

von temp (Gast)


Lesenswert?

Das liegt daran, dass der gcc hier so intelligent ist, dass für
1
  sprintf(buffer, "Test");

kein sprintf nötig ist, sondern ein strcpy reicht. Und wenn du sonst 
nirgends sprintf und co verwendest, wird es auch nicht dazu gelinkt. Da 
für strcpy kein Heap benötigt wird kommt es auch nicht zum Fehler.

Als Alternative empfehle ich hier eine abgespeckte Version von 
(sn)printf die ohne dynamischen Speicher auskommt. Dazu dürfte Google 
reichlich Treffer liefern.

von Manollo139 (Gast)


Lesenswert?

Hier mal mein kompletter Quellcode für das Testprojekt in dem ich den 
sprintf ans laufen bekommen möchte.
Mit printf werde ich das ganze jetzt erstmal versuchen.
Wäre aber über weitere tipps schonmal dankbar :-)

/**
 ************************************************************************ 
******
 * File Name          : main.c
 * Date               : 26/05/2015 12:44:11
 * Description        : Main program body
 ************************************************************************ 
******
 *
 * COPYRIGHT(c) 2015 STMicroelectronics
 *
 * Redistribution and use in source and binary forms, with or without 
modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright 
notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above 
copyright notice,
 *      this list of conditions and the following disclaimer in the 
documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its 
contributors
 *      may be used to endorse or promote products derived from this 
software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
"AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ************************************************************************ 
******
 */

/* Includes 
------------------------------------------------------------------*/

#include "stm32f0xx_hal.h"
#include <stdio.h>

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables 
---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes 
-----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void) {

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU 
Configuration----------------------------------------------------------* 
/

  /* Reset of all peripherals, Initializes the Flash interface and the 
Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1) {

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    char buffer[100] = "";
    uint8_t i = 1;
    sprintf(buffer, "Test %u",i);
    //sprintf(buffer, "Value of Pi ");

    //HAL_UART_Transmit(&huart1, (char*) buffer, 100, 100);
    //HAL_Delay(1000);

  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
 */
void SystemClock_Config(void) {

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
  RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);

  __SYSCFG_CLK_ENABLE();

}

/* USART1 init function */
void MX_USART1_UART_Init(void) {

  huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  huart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  HAL_UART_Init(&huart1);

}

/** Configure pins as
 * Analog
 * Input
 * Output
 * EVENT_OUT
 * EXTI
 PA2   ------> TSC_G1_IO3
 PA3   ------> TSC_G1_IO4
 PA6   ------> TSC_G2_IO3
 PA7   ------> TSC_G2_IO4
 PB0   ------> TSC_G3_IO2
 PB1   ------> TSC_G3_IO3
 PB10   ------> I2C2_SCL
 PB11   ------> I2C2_SDA
 PB13   ------> SPI2_SCK
 PB14   ------> SPI2_MISO
 PB15   ------> SPI2_MOSI
 */
void MX_GPIO_Init(void) {

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOC_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();

  /*Configure GPIO pins : PC0 PC5 PC6 PC7
   PC8 PC9 */
  GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_5 | GPIO_PIN_6 | 
GPIO_PIN_7
      | GPIO_PIN_8 | GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pins : PC1 PC2 */
  GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PA2 PA3 PA6 PA7 */
  GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6 | 
GPIO_PIN_7;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF3_TSC;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB0 PB1 */
  GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF3_TSC;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PB10 PB11 */
  GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF1_I2C2;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PB13 PB14 PB15 */
  GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

#ifdef USE_FULL_ASSERT

/**
 * @brief Reports the name of the source file and the source line number
 * where the assert_param error has occurred.
 * @param file: pointer to the source file name
 * @param line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and 
line number,
   ex: printf("Wrong parameters value: file %s on line %d\r\n", file, 
line) */
  /* USER CODE END 6 */

}

#endif

/**
 * @}
 */

/**
 * @}
 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF 
FILE****/

von Manollo139 (Gast)


Lesenswert?

Bezüglich der Aussage zur Buffergröße.
Ich hatte testweise auch mal 32,100,200 usw getestet.
Brachte keine Besserung.

von temp (Gast)


Lesenswert?

Am Ende wird von der newlib immer die Funktion
1
char *sbrk(int increment);

gerufen. Die muss passend implementiert sein. Wie das bei dir aussieht 
kann nur der startup-Code und das Linkerscript beantworten. Dabei wirst 
du dich aber auf den Hintern setzten, wenn du siehst wieviel Speicher da 
angefordert wird für dein simples Beispiel. Und vergiss eins nie: 
Solange die sbrk-Funktion nicht thread- bzw. interruptsaved programmiert 
ist, kannst du diese Funktionen (egal ob printf oder sprintf oder all 
die so ähnlich heissen) nicht ohne besondere Vorkehrungen in Interrupts 
verwenden.
Deshalb gebe ich dir nochmal dringend den Rat eine kleine Alternative zu 
verwenden, die ohne dynamischen Speicher auskommt.

von LTC1043 (Gast)


Lesenswert?

Wenn du wenig Flash hast (was beim F072 schnell der Fall ist) schau dir 
mal die sehr kompkte Lib von fleissigen Chan an:

http://elm-chan.org/fsw/strf/xprintf.html

Cheers

von W.S. (Gast)


Lesenswert?

Manollo139 schrieb:
> char buffer[100] = "";
>     uint8_t i = 1;
>     sprintf(buffer, "Test %u",i);
>     //sprintf(buffer, "Value of Pi ");
>
>     //HAL_UART_Transmit(&huart1, (char*) buffer, 100, 100);
>     //HAL_Delay(1000);

Huch? War's das etwa?
Und dafür braucht man ein sprintf() ?

Wenn ich solchen Quellcode sehe, krieg ich regelmäßig ganz schlechte 
Laune.

Also: für 99.99975 Prozent aller Textausgaben aus einem µC auf irgend 
einen verdammten Kanal - ob nun UART oder CDC oder sonstwas - braucht 
man alles mögliche andere, zum Beispiel eine gepufferte Ausgabe, die im 
Hintergrund ihren Job verrichtet, ohne daß man sowas wie 
"HAL_UART_Transmit" oder gar "HAL_Delay" bräuchte -

       ABER KEIN SPRINTF

und Konsorten. Zum Kuckuck nochmal.

W.S.

von temp (Gast)


Lesenswert?

W.S. schrieb:
> Also: für 99.99975 Prozent aller Textausgaben aus einem µC auf irgend
> einen verdammten Kanal

Die genaue Zahl ist 99.99976 ...

Hier ging es darum warum sprintf nicht geht und nicht warum man es 
einsetzt. Du hast zwar Recht, dass es nicht immer nötig ist, aber 
deswegen musst du am frühen Morgen keine schlechte Laune kriegen. Hab 
ich mir auch abgewöhnt, obwohl ich schon Kotzen könnte wenn ich sehe, 
was aus trivialen Sachen für Code entsteht wenn man die Libs von ST 
benutzt.

von Manollo139 (Gast)


Lesenswert?

Habe das Problem lösen können!

Habe mein Makefile um folgende Zeile ergänzt.
LDFLAGS += -u _printf_float

Gruß

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.