Author Topic: Rant... Why I dumped Platform IO IDE after a week  (Read 32377 times)

0 Members and 5 Guests are viewing this topic.

Offline Whales

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: au
    • Halestrom
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #25 on: September 10, 2022, 11:20:35 am »
- "Will you be able to build the project in 10 years?". EEV Members warn/warned others about this. I say no. I could barely build today, and that was not using any of their tooling, just bringing my own files in like a big boy. I initially scoffed this warning, but I recant. Their package manager looks nice, but it's trying to do too much. For STM32, they have a hard coded "platform" build script that tries to replace CubeMX and select the files you might need. I don't trust they will maintain it. I decided early to bring my own files in and it was also trouble.

My current PIO work codebase: we commit the whole .pio folder to git, because it's easier to keep a working setup going than fix things all of the time when doing a fresh clone and build.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 5292
  • Country: gb
  • Doing electronics since the 1960s...
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #26 on: September 10, 2022, 12:41:22 pm »
Quote
Vendor frameworks, IDEs and whatever have always been pure shit, and so are third party replacements.

Even if some are remotely acceptable, learning them is wasted time because they have short lifespans, or narrow scope (some specific brand).

I agree with the 1st but not with the 2nd. Stuff like a graphic IDE, with breakpoints, etc, is a real productivity enhancer. Even if it crashes quite a lot.

Actually I don't get why the 1st is true but it seems to be. The money made on chips (ST = $14BN sales) is so huge. They could do great tools. The mfgs are just taking the piss.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline hans

  • Super Contributor
  • ***
  • Posts: 1857
  • Country: 00
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #27 on: September 10, 2022, 01:53:31 pm »
I think HAL's are also a way to lure beginners and intermediaries to a vendor lock in.

If you look at hardware on a RTL level, then most operate almost identically. Where each bit is implementation details. Virtually any peripheral is structured the same: control registers, status registers, interrupt status/clear flag registers, and some data and auxillary registers.. for many many peripherals.
If I need to set up something new, I just set everything to zero and begin bringing in the stuff I need 1 by 1. That often works pretty well. Sometimes I will need to read some software description manual, e.g. how to set up the correct interrupts, DMA channels, FIFO's, initialization locks and delays, etc. But those are again implementation details..

Imagine if the manufacturer writes their HAL wrapper around it and immensely invest into frameworks, code generators, etc. Whoila you have an eco-system that should be great beginners or to get something done quickly (if there are no quirks and bugs, of course).
The problem is:

A) Eco-system is synonym a prison, especially in the enterprise world.
B) Backporting new HALs and frameworks could be a mess if the mfgr doesn't care about breaking changes

In software dev world you would seriously consider each dependency you add to a project, for the same reason as B, but also potentially if the project gets shitcanned by a company or OSS community and you're stuck with a soon-to-be outdated dependency.
Now in embedded this is often less of a problem. Many projects used a custom design/MCU. If the code works and is done (no more feature development), then eventually enough bugs have been squashed and in a few years time, the project has become 'legacy'.

Concerning point A): manufacturers will never have an interest in developing a compatible API of peripherals between devices. That's not an imprisonment for their customers, and so in the chance of e.g. a huge chip shortage it would be too easy/cheap for a customer to run to NXP/Microchip/SiLabs/etc. In contrast, ecosystems like Arduino, mbed, etc. are the closest to succeed in "compatible" APIs, however, but in those paradigms you will need to look up which ports have been assigned for various functions. E.g. on Arduino: which timer is used for ms timebase? Which serial port is reserved for using the bootloader and the default Serial object? Which I2C peripheral is used for the default Wire object? Which GPIOs are assigned to which analog/digital pinout on the original Arduino Uno form factor? And what if they conflict with an 'alternate' peripheral you need? Bad luck?

Now IMO ecosystems like Arduino are still some kind of imprisonment. Similar to how you can see many people ask about to use STM32 HAL's, or change over to a different chip/brand, etc. You see the similar thing happen for people moving away from Arduino. I get why it's attractive to use these paradigms to start learning or get something done (as I occasionally also do for quick projects), but in terms of control I think ecosystems will never deliver.
« Last Edit: September 10, 2022, 01:57:24 pm by hans »
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 5292
  • Country: gb
  • Doing electronics since the 1960s...
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #28 on: September 10, 2022, 02:20:18 pm »
I don't think one could develop a serious commercial product using the Cube MX type of code generation. No way.

MX is OK to get you started (the standard flashing LED :) ) and it is very handy for generating example code which you can copy into your real project and then discard the original, together with other obvious junk code. I have done that with a lot of ex MX code generated in the early days of my project.

I also don't think that changing CPU vendors is a real proposition in manufacturing. The current chip shortage is affecting everybody, at different times, like the carousel with wooden horses which go up and down. The proper solution is not to redesign with a different CPU (which involves a massive amount of work and so much retesting, unless the product is trivial) but to keep large stocks of strategic items. Forget JIT, which is just a fancy phrase for bending your small suppliers over a barrel and screwing them (and only large companies can do that). By all means use JIT for teabags, bog rolls, resistors, PCBs, etc. But not single sourced key items. At work I have at least 5 years' worth of CPU stock at all times (H8/3xx, now obsolete) and have probably a first year's production qty of the 32F417.

I know anything from Atmel is dodgy. I used the 90S1200 for years, and when I replaced it, by the time I went to buy some they had dropped those as well. But ST, like Hitachi, is a long term production company. They will probably run their chips for 20 years, and after that you can do a huge last time buy, and for a bit of time after that they come up on the US cowboy 2nd tier disti scene as companies dispose of dead stock. I bought tens of k of the H8s on that scene, for peanuts. Eventually the chinese found out there was a demand and started "printing" fake ones. That was the end, practically speaking. In the long run, it will pay you to a) stick with one big CPU company and b) hold strategically appropriate stock levels.

And then you can stick to the same software tools and not waste your time going up learning curves.

Well, it depends on whether you work for yourself or a company. If the latter, wasteful learning curves are ideal for putting bread on the table at home.
-----------------------------------------------------------------------------------
Simon edited to insert chinese instead of a term that apparently offends.
« Last Edit: September 10, 2022, 04:24:07 pm by Simon »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18615
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #29 on: September 10, 2022, 04:31:43 pm »
I have done the same, I have 1'000 SAMC chips in stock. They are a pain in the arse to work with as the datasheet is never clear about anything and the microchip code generator is a joke, but they were available and in time have potential. We will now be using them as general purpose port expanders and external ADC's as my colleague who I left to sort out the software side of things has fallen for the ESP32's which I have agreed to although somewhat nervous given that they are chinese and I always think long term. I'm interested in how the PI microcontroller type things turn out in comparison as perhaps a more stable alternative in the future.

 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 5292
  • Country: gb
  • Doing electronics since the 1960s...
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #30 on: September 10, 2022, 05:55:12 pm »
This is digressing but I would never use a chinese CPU. Incredibly risky politically - as well as their committment to anything to do with customers is only as long as a $100 bill. The ESP32 is a good package if you want a working out of the box TCP/IP + WIFI solution.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online JPortici

  • Super Contributor
  • ***
  • Posts: 3788
  • Country: it
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #31 on: September 10, 2022, 06:56:50 pm »
And yet GigaDevice has the only other mcu i could find, other than dsPIC33CK, that has CAN/CAN-FD in 28pin QFN (or other equally small package that isn't a massive pain to work with). Unfortunately they are not available either, but i was mentally ready to dive in.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17067
  • Country: fr
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #32 on: September 10, 2022, 07:02:58 pm »
Given how much of a hell it is right now to find MCUs, that's understandable.

I'm really considering making my own MCUs. ;D
(Of course that wouldn't solve the problem, as I would have even less access to foundries than the big ones, and sure, unit cost would be way higher unless I made millions of them.)

So that's just a musing right now more than a practical thought. But I do have a working RV32/RV64 core, a small set of peripherals (that I could easily expand), working I/D cache, a decent interrupt controller. For now it's fun on FPGAs, but that could be made on silicon. I dont have the cash though. :-DD
 
The following users thanked this post: tellurium

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18615
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #33 on: September 10, 2022, 07:57:10 pm »
Oh just turn to indigogo, they will fund anything
 

Offline Sal Ammoniac

  • Super Contributor
  • ***
  • Posts: 1805
  • Country: us
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #34 on: September 10, 2022, 11:20:40 pm »
I'll take another look at getting a VSCode development environment set up with the link jnz posted. I use STM32 rather than NXP, but the translation should be straightforward. In the meantime I'll continue using Segger Embedded Studio. Despite what others have said about it, it works well for me and I haven't had it crash for many years now--it's very stable, at least on my development system. I like it not because it has a great editor (it doesn't) or the newest, coolest features (it doesn't) but because it was the easiest of the graphical IDEs to get working with my projects from scratch. Much easier than STM32CubeIDE (and Atollic before that) or Keil and it just works. For debugging I mostly use Ozone.

I tried Keil a few months ago right after ARM removed the 32K code size limitation, but getting it working was a real pain in the ass, and I remember (although my memory of this is fading) issues with the C compiler version and associated assembler where I needed to compile C code with one version and assembly code with another because the assembly syntax changed (and I didn't want to convert all of my assembly to the new syntax).

Regarding MCU availability, yes, that's a problem for some, but I do this as a hobby and only do 3-4 projects a year, so my needs are modest. I was fortunate to anticipate a possible MCU shortage at the beginning of the pandemic and order a five year supply of the STM32F7 and H7 MCUs I use in projects, so I'm set (at least for now).
"That's not even wrong" -- Wolfgang Pauli
 

Offline artag

  • Super Contributor
  • ***
  • Posts: 1449
  • Country: gb
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #35 on: September 10, 2022, 11:25:49 pm »
I think HAL's are also a way to lure beginners and intermediaries to a vendor lock in.


That's not the intention : it's a (L)ayer supposed to (A)bstract the (H)ardware. But it's what ST's HAL does  - it isn't really a HAL, it's more like an OS or an API for devices .. that's so comprehensive that only other (ST) devices have it available. And also slugs the performance by using dreadful 'universal' code, so that you lose all the advantages of a bare-metal microcontroller.
 
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 5292
  • Country: gb
  • Doing electronics since the 1960s...
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #36 on: September 11, 2022, 06:13:28 am »
ST "HAL" is automatically generated code from Cube MX. It is a kind of hardware abstraction layer but really it is a load of code which you don't need to write yourself after reading the 2000 page RM :)

This is an example of ST HAL. Each function was written by somebody originally, and when you specify what you want in your project, it drops these functions into a file.

Code: [Select]
/**
  ******************************************************************************
  * @file    usbd_msc_scsi.c
  * @author  MCD Application Team
  * @brief   This file provides all the USBD SCSI layer functions.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2015 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                      [url=http://www.st.com/SLA0044]www.st.com/SLA0044[/url]
  *
  ******************************************************************************
  */

/* BSPDependencies
- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
- "stm32xxxxx_{eval}{discovery}_io.c"
- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c"
EndBSPDependencies */

/* Includes ------------------------------------------------------------------*/
#include "usbd_msc_bot.h"
#include "usbd_msc_scsi.h"
#include "usbd_msc.h"
#include "usbd_msc_data.h"


/** @addtogroup STM32_USB_DEVICE_LIBRARY
  * @{
  */


/** @defgroup MSC_SCSI
  * @brief Mass storage SCSI layer module
  * @{
  */

/** @defgroup MSC_SCSI_Private_TypesDefinitions
  * @{
  */
/**
  * @}
  */


/** @defgroup MSC_SCSI_Private_Defines
  * @{
  */

/**
  * @}
  */


/** @defgroup MSC_SCSI_Private_Macros
  * @{
  */
/**
  * @}
  */


/** @defgroup MSC_SCSI_Private_Variables
  * @{
  */

/**
  * @}
  */


/** @defgroup MSC_SCSI_Private_FunctionPrototypes
  * @{
  */
static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_RequestSense(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_AllowPreventRemovable(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_ModeSense6(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_ModeSense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
                                     uint32_t blk_offset, uint32_t blk_nbr);

static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun);
static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun);

static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc,
                                 uint8_t *pBuff, uint16_t length);
/**
  * @}
  */


/** @defgroup MSC_SCSI_Private_Functions
  * @{
  */


/**
* @brief  SCSI_ProcessCmd
*         Process SCSI commands
* @param  pdev: device instance
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *cmd)
{
  int8_t ret;
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  switch (cmd[0])
  {
  case SCSI_TEST_UNIT_READY:
    ret = SCSI_TestUnitReady(pdev, lun, cmd);
    break;

  case SCSI_REQUEST_SENSE:
    ret = SCSI_RequestSense(pdev, lun, cmd);
    break;

  case SCSI_INQUIRY:
    ret = SCSI_Inquiry(pdev, lun, cmd);
    break;

  case SCSI_START_STOP_UNIT:
    ret = SCSI_StartStopUnit(pdev, lun, cmd);
    break;

  case SCSI_ALLOW_MEDIUM_REMOVAL:
    ret = SCSI_AllowPreventRemovable(pdev, lun, cmd);
    break;

  case SCSI_MODE_SENSE6:
    ret = SCSI_ModeSense6(pdev, lun, cmd);
    break;

  case SCSI_MODE_SENSE10:
    ret = SCSI_ModeSense10(pdev, lun, cmd);
    break;

  case SCSI_READ_FORMAT_CAPACITIES:
    ret = SCSI_ReadFormatCapacity(pdev, lun, cmd);
    break;

  case SCSI_READ_CAPACITY10:
    ret = SCSI_ReadCapacity10(pdev, lun, cmd);
    break;

  case SCSI_READ_CAPACITY16:
    ret = SCSI_ReadCapacity16(pdev, lun, cmd);
    break;

  case SCSI_READ10:
    ret = SCSI_Read10(pdev, lun, cmd);
    break;

  case SCSI_READ12:
    ret = SCSI_Read12(pdev, lun, cmd);
    break;

  case SCSI_WRITE10:
    ret = SCSI_Write10(pdev, lun, cmd);
    break;

  case SCSI_WRITE12:
    ret = SCSI_Write12(pdev, lun, cmd);
    break;

  case SCSI_VERIFY10:
    ret = SCSI_Verify10(pdev, lun, cmd);
    break;

  default:
    SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_CDB);
    hmsc->bot_status = USBD_BOT_STATUS_ERROR;
    ret = -1;
    break;
  }

  return ret;
}


/**
* @brief  SCSI_TestUnitReady
*         Process SCSI Test Unit Ready Command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(params);
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  /* case 9 : Hi > D0 */
  if (hmsc->cbw.dDataLength != 0U)
  {
    SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);

    return -1;
  }

  if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)
  {
    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
    hmsc->bot_state = USBD_BOT_NO_DATA;
    return -1;
  }

  if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->IsReady(lun) != 0)
  {
    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
    hmsc->bot_state = USBD_BOT_NO_DATA;

    return -1;
  }
  hmsc->bot_data_length = 0U;

  return 0;
}


/**
* @brief  SCSI_Inquiry
*         Process Inquiry command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  uint8_t *pPage;
  uint16_t len;
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  if (hmsc->cbw.dDataLength == 0U)
  {
    SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
    return -1;
  }

  if ((params[1] & 0x01U) != 0U) /* Evpd is set */
  {
    if (params[2] == 0U) /* Request for Supported Vital Product Data Pages*/
    {
      (void)SCSI_UpdateBotData(hmsc, MSC_Page00_Inquiry_Data, LENGTH_INQUIRY_PAGE00);
    }
    else if (params[2] == 0x80U) /* Request for VPD page 0x80 Unit Serial Number */
    {
      (void)SCSI_UpdateBotData(hmsc, MSC_Page80_Inquiry_Data, LENGTH_INQUIRY_PAGE80);
    }
    else /* Request Not supported */
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST,
                     INVALID_FIELED_IN_COMMAND);

      return -1;
    }
  }
  else
  {
    pPage = (uint8_t *)&((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN];
    len = (uint16_t)pPage[4] + 5U;

    if (params[4] <= len)
    {
      len = params[4];
    }

    (void)SCSI_UpdateBotData(hmsc, pPage, len);
  }

  return 0;
}


/**
* @brief  SCSI_ReadCapacity10
*         Process Read Capacity 10 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(params);
  int8_t ret;
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  ret = ((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size);

  if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED))
  {
    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
    return -1;
  }

  hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 24);
  hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 16);
  hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >>  8);
  hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1U);

  hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >>  24);
  hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >>  16);
  hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >>  8);
  hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);

  hmsc->bot_data_length = 8U;

  return 0;

}


/**
* @brief  SCSI_ReadCapacity16
*         Process Read Capacity 16 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(params);
  uint8_t idx;
  int8_t ret;
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  ret = ((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size);

  if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED))
  {
    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
    return -1;
  }

  hmsc->bot_data_length = ((uint32_t)params[10] << 24) |
                          ((uint32_t)params[11] << 16) |
                          ((uint32_t)params[12] <<  8) |
                           (uint32_t)params[13];

  for (idx = 0U; idx < hmsc->bot_data_length; idx++)
  {
    hmsc->bot_data[idx] = 0U;
  }

  hmsc->bot_data[4] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 24);
  hmsc->bot_data[5] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 16);
  hmsc->bot_data[6] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >>  8);
  hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_nbr - 1U);

  hmsc->bot_data[8] = (uint8_t)(hmsc->scsi_blk_size >>  24);
  hmsc->bot_data[9] = (uint8_t)(hmsc->scsi_blk_size >>  16);
  hmsc->bot_data[10] = (uint8_t)(hmsc->scsi_blk_size >>  8);
  hmsc->bot_data[11] = (uint8_t)(hmsc->scsi_blk_size);

  hmsc->bot_data_length = ((uint32_t)params[10] << 24) |
                          ((uint32_t)params[11] << 16) |
                          ((uint32_t)params[12] <<  8) |
                           (uint32_t)params[13];

  return 0;
}


/**
* @brief  SCSI_ReadFormatCapacity
*         Process Read Format Capacity command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(params);
  uint16_t blk_size;
  uint32_t blk_nbr;
  uint16_t i;
  int8_t ret;
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  ret = ((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->GetCapacity(lun, &blk_nbr, &blk_size);

  if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED))
  {
    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
    return -1;
  }

  for (i = 0U; i < 12U ; i++)
  {
    hmsc->bot_data[i] = 0U;
  }

  hmsc->bot_data[3] = 0x08U;
  hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1U) >> 24);
  hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1U) >> 16);
  hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1U) >>  8);
  hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1U);

  hmsc->bot_data[8] = 0x02U;
  hmsc->bot_data[9] = (uint8_t)(blk_size >>  16);
  hmsc->bot_data[10] = (uint8_t)(blk_size >>  8);
  hmsc->bot_data[11] = (uint8_t)(blk_size);

  hmsc->bot_data_length = 12U;

  return 0;
}


/**
* @brief  SCSI_ModeSense6
*         Process Mode Sense6 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_ModeSense6(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(lun);
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;
  uint16_t len = MODE_SENSE6_LEN;

  if (params[4] <= len)
  {
    len = params[4];
  }

  (void)SCSI_UpdateBotData(hmsc, MSC_Mode_Sense6_data, len);

  return 0;
}


/**
* @brief  SCSI_ModeSense10
*         Process Mode Sense10 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_ModeSense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(lun);
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;
  uint16_t len = MODE_SENSE10_LEN;

  if (params[8] <= len)
  {
    len = params[8];
  }

  (void)SCSI_UpdateBotData(hmsc, MSC_Mode_Sense10_data, len);

  return 0;
}


/**
* @brief  SCSI_RequestSense
*         Process Request Sense command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_RequestSense(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(lun);
  uint8_t i;
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  if (hmsc->cbw.dDataLength == 0U)
  {
    SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
    return -1;
  }

  for (i = 0U; i < REQUEST_SENSE_DATA_LEN; i++)
  {
    hmsc->bot_data[i] = 0U;
  }

  hmsc->bot_data[0] = 0x70U;
  hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6U;

  if ((hmsc->scsi_sense_head != hmsc->scsi_sense_tail))
  {
    hmsc->bot_data[2] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;
    hmsc->bot_data[12] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;
    hmsc->bot_data[13] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;
    hmsc->scsi_sense_head++;

    if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
    {
      hmsc->scsi_sense_head = 0U;
    }
  }

  hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;

  if (params[4] <= REQUEST_SENSE_DATA_LEN)
  {
    hmsc->bot_data_length = params[4];
  }

  return 0;
}


/**
* @brief  SCSI_SenseCode
*         Load the last error code in the error list
* @param  lun: Logical unit number
* @param  sKey: Sense Key
* @param  ASC: Additional Sense Code
* @retval none

*/
void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
{
  UNUSED(lun);
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey;
  hmsc->scsi_sense[hmsc->scsi_sense_tail].w.b.ASC = ASC;
  hmsc->scsi_sense[hmsc->scsi_sense_tail].w.b.ASCQ = 0U;
  hmsc->scsi_sense_tail++;

  if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
  {
    hmsc->scsi_sense_tail = 0U;
  }
}


/**
* @brief  SCSI_StartStopUnit
*         Process Start Stop Unit command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(lun);
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  if ((hmsc->scsi_medium_state == SCSI_MEDIUM_LOCKED) && ((params[4] & 0x3U) == 2U))
  {
    SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);

    return -1;
  }

  if ((params[4] & 0x3U) == 0x1U) /* START=1 */
  {
    hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
  }
  else if ((params[4] & 0x3U) == 0x2U) /* START=0 and LOEJ Load Eject=1 */
  {
    hmsc->scsi_medium_state = SCSI_MEDIUM_EJECTED;
  }
  else if ((params[4] & 0x3U) == 0x3U) /* START=1 and LOEJ Load Eject=1 */
  {
    hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
  }
  else
  {
    /* .. */
  }
  hmsc->bot_data_length = 0U;

  return 0;
}


/**
* @brief  SCSI_AllowPreventRemovable
*         Process Allow Prevent Removable medium command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_AllowPreventRemovable(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(lun);
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  if (params[4] == 0U)
  {
    hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
  }
  else
  {
    hmsc->scsi_medium_state = SCSI_MEDIUM_LOCKED;
  }

  hmsc->bot_data_length = 0U;

  return 0;
}


/**
* @brief  SCSI_Read10
*         Process Read10 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
  {
    /* case 10 : Ho <> Di */
    if ((hmsc->cbw.bmFlags & 0x80U) != 0x80U)
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)
    {
      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);

      return -1;
    }

    if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->IsReady(lun) != 0)
    {
      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
      return -1;
    }

    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
                          ((uint32_t)params[3] << 16) |
                          ((uint32_t)params[4] <<  8) |
                          (uint32_t)params[5];

    hmsc->scsi_blk_len = ((uint32_t)params[7] <<  8) | (uint32_t)params[8];

    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
                               hmsc->scsi_blk_len) < 0)
    {
      return -1; /* error */
    }

    /* cases 4,5 : Hi <> Dn */
    if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size))
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    hmsc->bot_state = USBD_BOT_DATA_IN;
  }
  hmsc->bot_data_length = MSC_MEDIA_PACKET;

  return SCSI_ProcessRead(pdev, lun);
}


/**
* @brief  SCSI_Read12
*         Process Read12 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
  {
    /* case 10 : Ho <> Di */
    if ((hmsc->cbw.bmFlags & 0x80U) != 0x80U)
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)
    {
      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
      return -1;
    }

    if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->IsReady(lun) != 0)
    {
      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
      return -1;
    }

    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
                          ((uint32_t)params[3] << 16) |
                          ((uint32_t)params[4] <<  8) |
                          (uint32_t)params[5];

    hmsc->scsi_blk_len = ((uint32_t)params[6] << 24) |
                         ((uint32_t)params[7] << 16) |
                         ((uint32_t)params[8] << 8) |
                         (uint32_t)params[9];

    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
                               hmsc->scsi_blk_len) < 0)
    {
      return -1; /* error */
    }

    /* cases 4,5 : Hi <> Dn */
    if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size))
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    hmsc->bot_state = USBD_BOT_DATA_IN;
  }
  hmsc->bot_data_length = MSC_MEDIA_PACKET;

  return SCSI_ProcessRead(pdev, lun);
}


/**
* @brief  SCSI_Write10
*         Process Write10 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;
  uint32_t len;

  if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
  {
    if (hmsc->cbw.dDataLength == 0U)
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    /* case 8 : Hi <> Do */
    if ((hmsc->cbw.bmFlags & 0x80U) == 0x80U)
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    /* Check whether Media is ready */
    if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->IsReady(lun) != 0)
    {
      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
      return -1;
    }

    /* Check If media is write-protected */
    if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->IsWriteProtected(lun) != 0)
    {
      SCSI_SenseCode(pdev, lun, NOT_READY, WRITE_PROTECTED);
      return -1;
    }

    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
                          ((uint32_t)params[3] << 16) |
                          ((uint32_t)params[4] << 8) |
                          (uint32_t)params[5];

    hmsc->scsi_blk_len = ((uint32_t)params[7] << 8) |
                         (uint32_t)params[8];

    /* check if LBA address is in the right range */
    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
                               hmsc->scsi_blk_len) < 0)
    {
      return -1; /* error */
    }

    len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;

    /* cases 3,11,13 : Hn,Ho <> D0 */
    if (hmsc->cbw.dDataLength != len)
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    len = MIN(len, MSC_MEDIA_PACKET);

    /* Prepare EP to receive first data packet */
    hmsc->bot_state = USBD_BOT_DATA_OUT;
    (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
  }
  else /* Write Process ongoing */
  {
    return SCSI_ProcessWrite(pdev, lun);
  }

  return 0;
}


/**
* @brief  SCSI_Write12
*         Process Write12 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;
  uint32_t len;

  if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
  {
    if (hmsc->cbw.dDataLength == 0U)
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    /* case 8 : Hi <> Do */
    if ((hmsc->cbw.bmFlags & 0x80U) == 0x80U)
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    /* Check whether Media is ready */
    if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->IsReady(lun) != 0)
    {
      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
      hmsc->bot_state = USBD_BOT_NO_DATA;
      return -1;
    }

    /* Check If media is write-protected */
    if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->IsWriteProtected(lun) != 0)
    {
      SCSI_SenseCode(pdev, lun, NOT_READY, WRITE_PROTECTED);
      hmsc->bot_state = USBD_BOT_NO_DATA;
      return -1;
    }

    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
                          ((uint32_t)params[3] << 16) |
                          ((uint32_t)params[4] << 8) |
                          (uint32_t)params[5];

    hmsc->scsi_blk_len = ((uint32_t)params[6] << 24) |
                         ((uint32_t)params[7] << 16) |
                         ((uint32_t)params[8] << 8) |
                         (uint32_t)params[9];

    /* check if LBA address is in the right range */
    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
                               hmsc->scsi_blk_len) < 0)
    {
      return -1; /* error */
    }

    len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;

    /* cases 3,11,13 : Hn,Ho <> D0 */
    if (hmsc->cbw.dDataLength != len)
    {
      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
      return -1;
    }

    len = MIN(len, MSC_MEDIA_PACKET);

    /* Prepare EP to receive first data packet */
    hmsc->bot_state = USBD_BOT_DATA_OUT;
    (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
  }
  else /* Write Process ongoing */
  {
    return SCSI_ProcessWrite(pdev, lun);
  }

  return 0;
}


/**
* @brief  SCSI_Verify10
*         Process Verify10 command
* @param  lun: Logical unit number
* @param  params: Command parameters
* @retval status
*/
static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  if ((params[1] & 0x02U) == 0x02U)
  {
    SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
    return -1; /* Error, Verify Mode Not supported*/
  }

  if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr, hmsc->scsi_blk_len) < 0)
  {
    return -1; /* error */
  }

  hmsc->bot_data_length = 0U;

  return 0;
}

/**
* @brief  SCSI_CheckAddressRange
*         Check address range
* @param  lun: Logical unit number
* @param  blk_offset: first block address
* @param  blk_nbr: number of block to be processed
* @retval status
*/
static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
                                     uint32_t blk_offset, uint32_t blk_nbr)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;

  if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr)
  {
    SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
    return -1;
  }

  return 0;
}

/**
* @brief  SCSI_ProcessRead
*         Handle Read Process
* @param  lun: Logical unit number
* @retval status
*/
static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;
  uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;

  len = MIN(len, MSC_MEDIA_PACKET);

  if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->Read(lun, hmsc->bot_data,
                                                     hmsc->scsi_blk_addr,
                                                     (len / hmsc->scsi_blk_size)) < 0)
  {
    SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
    return -1;
  }

  (void)USBD_LL_Transmit(pdev, MSC_EPIN_ADDR, hmsc->bot_data, len);

  hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
  hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);

  /* case 6 : Hi = Di */
  hmsc->csw.dDataResidue -= len;

  if (hmsc->scsi_blk_len == 0U)
  {
    hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
  }

  return 0;
}

/**
* @brief  SCSI_ProcessWrite
*         Handle Write Process
* @param  lun: Logical unit number
* @retval status
*/
static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataMSC;
  uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;

  len = MIN(len, MSC_MEDIA_PACKET);

  if (((USBD_StorageTypeDef *)pdev->pClassSpecificInterfaceMSC)->Write(lun, hmsc->bot_data,
                                                      hmsc->scsi_blk_addr,
                                                      (len / hmsc->scsi_blk_size)) < 0)
  {
    SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, WRITE_FAULT);
    return -1;
  }

  hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
  hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);

  /* case 12 : Ho = Do */
  hmsc->csw.dDataResidue -= len;

  if (hmsc->scsi_blk_len == 0U)
  {
    MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_PASSED);
  }
  else
  {
    len = MIN((hmsc->scsi_blk_len * hmsc->scsi_blk_size), MSC_MEDIA_PACKET);

    /* Prepare EP to Receive next packet */
    (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
  }

  return 0;
}


/**
* @brief  SCSI_UpdateBotData
*         fill the requested Data to transmit buffer
* @param  hmsc handler
* @param  params: Data buffer
* @param  length: Data length
* @retval status
*/
static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc,
                                 uint8_t *pBuff, uint16_t length)
{
  uint16_t len = length;

  hmsc->bot_data_length = len;

  while (len != 0U)
  {
    len--;
    hmsc->bot_data[len] = pBuff[len];
  }

  return 0;
}
/**
  * @}
  */


/**
  * @}
  */


/**
  * @}
  */

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


Ask yourself how much research you would need to come up with the above code. Almost nobody knows anything about this. Your chances of writing MSC code by reading the RM is just about zero. You would have to lift code from around the internet. But you can reasonably expect ST code to work, whereas you can't reasonably expect something you found on Github to work - a lot of stuff posted there is just work in progress, terminated when the coder lost interest.

Admittedly a lot of it is bloated but if you are looking for some code, this is a good starting point to see what is required. Then you can chop out the bits which don't apply (e.g. SPI code which transmits out of the SPI, checking if CRC is enabled, but you never enabled CRC originally, so this wastes a few clocks on the conditional) and crucially you know where in the RM you need to look to understand the code. The problem with trying to write code just by reading the RM (which a number of super-experienced people on here and the ST forum tell you to do, usually forcefully, occassionally with extreme rudeness which would have them instantly fired from any job) is that it is hard to know where to start, and a lot of peripherals need stuff done in a certain order.

There are also plenty of mistakes in ST's code, which is another story. Basically, people who develop this way spend as much time as "RM readers" on googling to see who has been up this road before, to fix stuff which doesn't work properly.

So if I was to debate whether MX saves time, yes it saves a lot of time initially. In that sense ST Cube is a great tool. Afterwards, you can write your own bare metal code by reference to the RM, and googling for github code, of which on a good day 50% works :)

« Last Edit: September 11, 2022, 07:00:06 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 10348
  • Country: fi
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #37 on: September 11, 2022, 07:58:57 am »
That's not the intention : it's a (L)ayer supposed to (A)bstract the (H)ardware. But it's what ST's HAL does  - it isn't really a HAL, it's more like an OS or an API for devices

You have the terminology totally mixed up.

The only confusing thing in ST's HAL is using the generic term for a name, similar to selling chocolate under trade name "Chocolate", now how confusing is that.

Other than that, it is exactly what the name suggests, a HAL. It definitely is not an OS. API? The ST's HAL has an API. API is just a generic term for an interface; in a simple C module, the API is the set of function definitions that come in the .h file you #include.

Now the GPIO_Init_Struct type bullshit is really not a HAL but just a so-called boilerplate or bloat layer with no use. But HAL_Start_SPI_Transfer type thing is a HAL because it abstracts some details away and thus gains something.

But I understand the confusion, some call the autogenerated bullshit code by Cube "HAL", other's just call the ST's HAL library, which have the HAL prefix in function names, the HAL. The latter is an actual HAL. Former is a crappy code generator.
« Last Edit: September 11, 2022, 08:00:59 am by Siwastaja »
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 5292
  • Country: gb
  • Doing electronics since the 1960s...
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #38 on: September 11, 2022, 09:23:03 am »
IMHO "HAL" is a deliberately confusing marketing term.

Quote
GPIO_Init_Struct type bullshit is really not a HAL but just a so-called boilerplate or bloat layer with no use

It saves one reading quite a lot of the RM :) Basically you can avoid learning about AF mapping.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 10348
  • Country: fi
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #39 on: September 11, 2022, 02:32:52 pm »
It saves one reading quite a lot of the RM :) Basically you can avoid learning about AF mapping.

What are you talking about? The AF bitfields are exposed directly, as is, no abstraction, but no 1:1 memory correspondence either, so just downsides:

Code: [Select]
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
Sure, there is added peripheral name in that #define name but you wouldn't need any of the struct init function "abstraction" bullshit for that. That's exactly what every MCU vendor since early 1990's have been doing in their header files, say how PORTB is #defined so you don't need to remember the memory address yourself.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 5292
  • Country: gb
  • Doing electronics since the 1960s...
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #40 on: September 11, 2022, 06:40:08 pm »
I was thinking of the HAL functions which set up individual pins to be in, out, and the various types of in and out circuitry. They contain very convoluted code but are easy to get into.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline tellurium

  • Frequent Contributor
  • **
  • Posts: 310
  • Country: ua
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #41 on: September 11, 2022, 10:22:02 pm »
Language and Syntax:
ARM
C
CMake
...

Out of curiosity.. Why CMake? Why not a plain Make?  What is the point of learning an obscure Make generator instead of just writing Make yourself - which is quite easy?
Open source embedded network library https://mongoose.ws
TCP/IP stack + TLS1.3 + HTTP/WebSocket/MQTT in a single file
 
The following users thanked this post: Siwastaja

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17067
  • Country: fr
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #42 on: September 11, 2022, 10:32:39 pm »
CMake has become popular for embedded development. It certainly brings some benefits, but I don't like it much myself. So I do stick to just makefiles. Much more flexible IMHO.

Also one point that annoys me to no end with CMake is how it tends to promote a very heavily hierarchical file structure. All projects I've seen built with CMake are structured this way. You practically have one source file per folder, with sometimes the header file yet in another subfolder and CMake files everywhere at every level. While I understand that it may make the whole project "tidier" and sligthly easier to reuse components in a given build environment, it's so nested and convoluted that it's a royal pain to set up and navigate. I hate it.

 
The following users thanked this post: bson, jnz, tellurium

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17067
  • Country: fr
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #43 on: September 12, 2022, 12:07:49 am »
Oh just turn to indigogo, they will fund anything

Oh sure. Probably workable with some shiny slides, a nice video and a few unmeetable promises.

Thing is, there's a world between designing a MCU for your own internal needs and designing one for direct market consumption. If you crowfund one, it would have to be the latter. Then you'd have to write proper documentation, include features and peripherals that you don't care about but that are needed for general-purpose use, and so on, and so forth.

And, as I said, access to foundries at the moment is a joke anyway. So, there would be nothing in the end. Maybe it'll get better next year. Or the year after. Or... you get the idea. I dunno.
Unfortunately.
 

Offline jnzTopic starter

  • Frequent Contributor
  • **
  • Posts: 593
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #44 on: September 12, 2022, 12:47:12 am »
On topic…

That link series I posted is on a site of a guy that likes NXP, but his guides for VS Code have stm32 examples.

The Segger EDU is super cheap. The only tool I would buy as a hobbiest.

Why CMake vs Make? For one, because I wanted to use Ninja. And Make is showing its age a bit. I wanted to be able to define functions and run other scripts during and after the build process, CMake and Ninja seemed better for this. You don’t have to lay things out in different folders/files, it supports any layout you want. Everything makes sense to me, so I have no real problem with it. Plus, if you don’t already know Make, it makes more sense to skip and go right on to CMake imo.

It doesn’t matter.

The only thing that PIO got definitely right imo was VSCode. They didn’t outright mess up with SCons but other decisions made that pointless.
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 578
  • Country: sk
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #45 on: September 12, 2022, 05:16:14 am »
Oh just turn to indigogo, they will fund anything
And, as I said, access to foundries at the moment is a joke anyway. So, there would be nothing in the end. Maybe it'll get better next year. Or the year after.

Crowdfund also a foundry, then... ;-)

JW
 

Offline analityk

  • Regular Contributor
  • *
  • Posts: 95
  • Country: pl
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #46 on: September 14, 2022, 07:05:52 pm »
Everything you wrote is true. This python scripts for easy build your solution works on default (compilable) setting and if you need something more that's fail. Problems is this software pack for stm and python scripts.
Some days ago I watch on yt channel where someone explain and show how to install arm toolchain, gdb, make for windows, git etc.
I spent many hours but successfuly compiled solution from scratch, for stm32f7xx. Of course with gnu make etc.
This is hard way but it it is not dependent for vsc or platformio actualization. And I bet for 19 years compilation will be like today. Another valuable thing is i not need use of stm ide. It look like someone stop developing it in 1999.

Visual Studio code is only code editor, good but by default is like piece of shit and is unusable.
 

Offline tellurium

  • Frequent Contributor
  • **
  • Posts: 310
  • Country: ua
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #47 on: September 14, 2022, 07:20:11 pm »
This is hard way but it it is not dependent for vsc or platformio actualization. And I bet for 19 years compilation will be like today. Another valuable thing is i not need use of stm ide. It look like someone stop developing it in 1999.

I found ARM GCC toolchain and Make very easy to install and use; it is just a matter of minutes, not hours.

What is not trivial, if we're speaking about bare metal approach, is 1) linker script and 2) initialization / boot code. The rest is easy peasy.

Can you point out, what exactly took hours, and was hard?
Open source embedded network library https://mongoose.ws
TCP/IP stack + TLS1.3 + HTTP/WebSocket/MQTT in a single file
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17067
  • Country: fr
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #48 on: September 14, 2022, 07:26:53 pm »
To get started with the linker script and startup code, just take the ones that are provided by the vendor. They are always there in their SDKs.
Then you can always modify them to suit your particular needs, but that's a working starting point.

Some people just assume that vendor SDKs/tools just magically make things happen. Nah, they are just tools that are generating or using all the same stuff behind the scenes: startup code, linker scripts, GCC (most of the time) and makefiles. (Those using CMake can go from there too. Either makefiles or Cmake files contain compiler and linker options, so that gives you the right options to use.)

You don't need to go through a mountain of docs to get started. Use vendor-provided stuff as they should be used (IMO): as a starting point. All you need is to dig a bit.
 
The following users thanked this post: tellurium

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4549
  • Country: us
Re: Rant... Why I dumped Platform IO IDE after a week
« Reply #49 on: September 14, 2022, 11:27:25 pm »
I think I miss having a "Corporate infrastructure" dictating the tools I have to use.  On the one hand, I might be forced into using something that I don't particularly like, at least initially.  On the other hand, it also implies an environment where there are enough users of those tools that I'll get "support" - people explaining how (and why) to use features that I wouldn't have noticed.  How to work around bugs.  The corporate "weight" to get the vendor (or a local tools team) to actually fix bugs.  Commiseration for those problems that aren't going to be fixed.

All I've learned from online fora is that there is no IDE that someone doesn't really hate.  IDEs that are too slow.  IDEs that are ugly.  IDEs that are too simple.  IDEs that are too complex.  IDEs that are too vendor-specific.  IDEs that require too much configuration to use with XXX.   Bah humbug!
 
The following users thanked this post: elecdonia


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf