S12 / MagniV Microcontrollers Knowledge Base

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

S12 / MagniV Microcontrollers Knowledge Base

Labels
  • General 44

Discussions

Sort by:
S12(X) MCU Secure: There’s a security byte in the flash memory at address 0xFF0F that should be programmed appropriately. Datasheet says: “The contents of the Flash Protection/Options byte at $FF0F in the Flash Protection/Options Field must be changed directly by programming $FF0F when the device is unsecured and the higher address sector is unprotected. If the Flash Protection/Options byte is left in the secure state, any reset will cause the MCU to return to the secure operating mode.”   If you use CodeWarrior then you can use the syntax as follows: const unsigned char secure @0xFF0F = 0xFC;   If the security is enabled then: - internal flash memory cannot be read via BDM device. - debug features are disabled. For more information see the description of FSEC register in datasheet.   I would like also recommend our application note AN2400 HCS12 NVM Guidelines: http://www.freescale.com/files/microcontrollers/doc/app_note/AN2400.pdf AN2880 Using the Backdoor Access Capability to Unsecure HCS12 MCUs: http://www.freescale.com/files/microcontrollers/doc/app_note/AN2880.pdf http://www.freescale.com/webapp/sps/download/license.jsp?colCode=AN2880SW     Security at S12(X) MCUs with 180nm Flash: This is related to all S12(X) MCUs with 180nm Flash with ECC (S12G, S12HY, S12P, S12XE, S12XF, S12XHY,  S12XS, MM912G634, MM912H634, MM912J637 and S12VR):   If we load the flash security byte together with other code, ****************** c code example: //set backdoor key and secure the flash (set flash security byte to 0xBD): const unsigned char flash_array[] @0xFF00 = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBD}; ****************** then we have to add following command to preload command file (P&E_Multilink_USB_Preload.cmd if you use PE Multilink):   FLASH NOUNSECURE   This command will ensure that the burner will not change security byte to unsecured state prior to programming. That's normal way: the MCU is erased, flash security byte is programmed to default unsecure state (0xFE) and then the code is loaded. We just have to turn off the programming of security byte.   Why: The cumulative bits within the phrase is not allowed. If the flash security byte at address 0xFF0F is not erased prior to programming of the new value then the ECC checksum of this phrase is corrupted and the MCU will be left in secured state and the flash will be fully protected after next reset.   Datasheet says: "If a double bit fault is detected while reading the P-Flash phrase containing the P-Flash protection byte during the reset sequence, the FPOPEN bit will be cleared and remaining bits in the FPROT register will be set to leave the P-Flash memory fully protected."   "If a double bit fault is detected while reading the P-Flash phrase containing the Flash security byte during the reset sequence, all bits in the FSEC register will be set to leave the Flash module in a secured state with backdoor key access disabled."   The same for D-Flash...   S12(X) unsecure: Unsecure is possible by three ways: 1. Backdoor key access(temporary) 2. Reprogramming the security bits 3. Complete memory erase (special modes) Ad1) For secure and backdoor key you set 16bytes on address 0xFF00. The backdoor key access method allows debugging of a secured microcontroller without having to erase the Flash. This is particularly useful for failure analysis. For unsecure by backdoor key you use special flash command 0C (caption Verify Backdoor Access Key Command in reference manual). No word of the backdoor key is allowed to have the value 0x0000 or 0xFFFF. Unsecure is valid only till reset. If an invalid attempt is made to verify the Backdoor Keys the command will be locked out until a power down occurs.  Ad2) In normal single chip mode (NS), security can also be disabled by erasing and reprogramming the security bits within Flash options/security byte to the unsecured value. Because the erase operation will erase the entire sector from 0xFE00–0xFFFF, the backdoor key and the interrupt vectors will also be erased; this method is not recommended for normal single chip mode. Ad3) Complete mass erase by BDM device(in special mode). In Code Warior debugger menu ->MultilinkCyclonePro->Unsecure… If not work you can use unsecure12 from P&E: http://www.pemicro.com/downloads/download_file.cfm?download_id=16 Unsecure_12 Help Files: http://www.pemicro.com/downloads/download_file.cfm?download_id=14 Note: For downloading is necessary registration.
View full article
This short video demonstrates a path through NXP website to the CodeWarrior v5.1 download link. On the final place other downloads are available such as service packs, updates, patches etc. Login to NXP site is required.
View full article
The bold blue links below provide direct download of SW example packs for MagniV devices based on S12Z core.   S12ZVC Getting Started Exercises (REV 1.0) This file contains four hands-on exercise where you can find basic setup code to enable a quick development in different areas. The file includes CodeWarrior projects demonstrating usage of peripheral modules such as: - Digital-to-Analog Converter (DAC), - Controller Area Network (CAN), - Pulse Width Modulation (PWM), - Timer (TIM).   Getting started with S12ZVL32 - S12 MagniV Example Codes (REV 0) The MC9S12ZVC device integrates a battery level (12V) voltage regulator and supply voltage monitoring. This zipped file includes four CodeWarrior examples demonstrating - Overcurrent protection on EVDD pin, - low power STOP mode with API timer and wake-up feature, - Pulse Width Modulation (PWM) - Serial Peripheral Interface (SPI) communication.   Many of these examples can be used on various MCU families across the MagniV product line. Check the appropriate device guide for list of modules and its versions.
View full article
Introduction In many old-fashioned automotive motor control systems, PWM command communication is still preferred over LIN or CAN. Even for in-lab application debugging, it is very convenient to use PWM command communication to control the motor placed in a test-bench or in an acoustic or thermal chamber, especially when the BDM debugger or the SCI/RS232 communication is not available. PWM control is usually specified on the OEM level and it is not provided as a public standard. Nevertheless, adjustable software driver can be created to help the PWM command signal to be detected. The following code has been developed for S12ZVM, but it can be easily adopted to fit in whatever device with a timer input capture feature. Hardware specification may be different for many cases and the implementation is the matter of proper design case-by-case and may be a very easy task for a skilled designer. However, software design can be abstracted and reused for different hardware implementation. In order to help you use the PWM control signal, the following description is provided. The example provided is targeting NXP MagniV S12ZVML devices, but may be used along with any device accordingly. The S12ZVML MCU contains LIN physical layer which will be used as PWM input in our case. PWM Signal Specification Since there is no public standard specification on PWM signal, let's target a general case with adjustable parameters. Since the PWM control signal is being replaced by LIN communication, the specification may be based on 5.5V to 18V voltage range with nominal 12V level. PWM frequency varies from 10 Hz to 1 kHz (or more), but it really depends on the requirements of the application, compatibility, etc. Duty-cycle range of the PWM signal might be from 15% to 90% from stand-by to full speed. Hysteresis at low duty-cycle range (between 10 and 15%) prevents the system from periodic on/off switching at the lowest duty-cycle. Duty-cycles outside of this range may be identified as not valid and appropriate action may be taken (e.g. full speed command to an engine cooling fan). The signal definition should consider some specific values to help with the signal reading. Following values are defined: Label Description noSignalLevel No signal detected below this duty cycle noSignalOutput Output on "no signal" detected lowSignalOutput Output on "low signal" detected hystLowSignalOff Low level of the hysteresis. Smaller duty-cycle means "low signal" state, higher duty-cycle enters the hysteresis range (min speed or stand-by) hystLowSignalOn High level of the hysteresis. Smaller duty-cycle means "hysteresis area: min speed or stand-by", higher duty-cycle means "run"  in the linear signal range, with the speed given by the duty-cycle. linearSignalOutputMin Low level of the linear mode linearSignalLevelMax High level of the linear mode Considering normal operation in stand-by mode, the duty-cycle is between noSignalLevel and hystLowSignalOff. In order to add some distortion-proof feature, the duty-cycle can go up to the hystLowSignalOn and the stand-by mode would be still detected. In order to engage the "run" state, the duty-cycle has to exceed the hystLowSignalOn value and the linear area is reached. Corresponding output is calculated to meet the linearSignalOutputMin at the hystLowSignalOn value and linearSignalOutputMax at the linearSignalLevelMax. System keeps the output at linearSignalOutputMax for duty-cycles higher than linearSignalLevelMax. When slowing down, reaching the hystLowSignalOn sets the output to linearSignalOutputMin and keeps this output until the hystLowSignalOff is reached. This way, the hysteresis feature is provided in order to prevent motors from randomly switch on and off in case the PWM signal is noisy. Lowering the duty-cycle below the hystLowSignalOff, zero output is set, which represents the stand- by mode. Duty-cycles below the noSignalLevel are treated as not valid and noSignalOutput is engaged (which can be set to zero or to max, according to the application requirements). Requirements on Timer In order to correctly detect PWM signal frequency and duty-cycle, hardware timer with input capture feature and rising/falling edges detection shall be used. Timing and chaining of multiple timer channels may be needed to increase the frequency range or duty-cycle resolution. Following example will be simplified to use just one 16-bit timer channel (timer module TIM16B4CV3 used in S12ZVML128). The input of the timer shall be routed to an input pin, on which the PWM signal will be sensed. Integrated LIN physical layer module of S12ZVML128 device can be used for signal conditioning since the signal voltage range is up to 18V. In the example, LINPhy module has to be enabled and the LPRXD0 signal is routed to the timer T0 input capture channel 3 by setting "T0IC3RR1-0" of the MODRR2 register to 0b01. Input capture and timer overflow interrupts are used to detect correct or faulty signal. Requirements on Application Software PWM signal detection is called within the Timer Input Capture interrupt. This way, the duty-cycle is calculated immediately. Signal lost event is detected within the Timer overflow interrupt. It is recommended that the detected duty-cycle is filtered by a low-pass filter (moving average or IIR), which is usually called within some real-time interrupt routine, such as PWM reload or ADC end-of-scan interrupt. Reading of the output value can be done anytime within the code, e.g. within a speed loop to read the demanded speed command. Algorithm Description Frequency and Duty-cycle Detection Frequency of PWM signal is given by the time between two consecutive rising edges or two falling edges. The duty-cycle is a ratio between the time of high-level state over the entire period, as indicated below. The key is to capture the time of the rising edge tR1, change the detection mode to the falling edge to capture the time of the falling edge tF1, again change the detection mode to rising edge, etc. This detection can be easily done within the input capture timer interrupt. The time values captured are then used to calculate "High" and "Period" values. Frequency and duty-cycle is calculated based on the following equations. The timer settings should follow requirements on frequency range and duty-cycle resolution. It is recommended that the timer settings allow detecting frequencies slightly beyond the required frequency range. Let's consider an example of: Limit Specified frequency limits Detected frequency Detected period Minimal PWM frequency 20 Hz 19.5 Hz 0.051282 s Maximal PWM frequency 1000 Hz 1010 Hz 0.00099 s Based on these limits, Timer settings can be calculated, considering the MCU clock settings and prescalers: For example, if the fbus = 50 MHz and the TimerPrescaler = 50, MinPeriodTicks for MaxDetectedFreq = 1010 Hz equals 495 ticks of the timer. The duty-cycle resolution at 1010 Hz is then 1/495, which is 0.202%. MaxPeriodTicks is key information for the timer settings since it needs to fit in the 16bit range with no overflow. In this case, the number of ticks is 25641 for 19.5Hz, which is suitable for 16-bit range with no issues. If the detected period (number of timer ticks) is outside of this range, the algorithm should go to the noSignalLevel state with defined noSignalOutput. Finally, if the PWM signal is lost or corrupted, timer overflow event occurs and corresponding interrupt is called. Within the interrupt routine, the entire algorithm should be reset to wait for another rising edge, while turned in the noSignalLevel state with defined noSignalOutput. Selecting Detected State Based on the PWM signal condition, frequency and duty-cycle detected, the algorithm state is selected. Following states are defined to help users with state identification: State Description Output  PWM_NoSignalDetect PWM signal is not detected or the PWM period is outside of the range noSignalOutput, usually zero or full command (according to the application requirements) PWM_LowSignalDetect PWM signal is detected, the duty-cycle is within the noSignalLevel and hystLowSignalOn or hystLowSignalOff (depends on the hysteresis) lowSignalOutput, usually zero/stand-by PWM_LinearCtrlDetect PWM signal is detected, the duty-cycle is within the hystLowSignalOn and linearSignalLevelMax output = (dutyCycle * linearSignalSlope + linearSignalOffset) << linearSignalNshift, from linearSignalOutputMin to linearSignalOutputMax PWM_HighSignalDetect PWM signal is detected, the duty-cycle is higher than linearSignalLevelMax linearSignalOutputMax Linear Output Calculation Linear output calculation is an easy way of interpolating two endpoints by a linear equation. In order to calculate the coefficients (slope and offset) and to improve the fixed point range, shifting is implemented as well. Algorithm Integration Interfaces The algorithm is designed as a set of static functions with a structure of settings as a parameter to all the interfaces. This way, the same functionality can be used in multiple instances.  /* PWM Control data structure */ typedef struct { pwmControlStatus_t flags; //Control status bits pwmControlConfig_t config; //Configuration unsigned int period; //Modulation period unsigned int dutyCycle; //dutyCycle unsigned int hystDutyCycle; //previous hysteresis of duty cycle #ifndef PWM_CONTROL_SW unsigned int overflowCntr; //timer overflow counter #endif tFrac16 outputValue; //Output value unsigned int ControlInputClass; //Classification of the input signal } pwmControl_t;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The input-output characteristics are defined by a set of parameters as discussed earlier using the following structure: typedef struct { /* No signal definition */ tFrac16 noSignalLevel; //Level of the duty cycle for NoSignal detection tFrac16 noSignalOutput; //Output when NoSignal is detected /* Low signal definition */ tFrac16 lowSignalOutput; //Output when LowSignal is detected /* Linear signal definition */ tFrac16 hystLowSignalOff; //LowSignal-to-NoSignal hysteresis level tFrac16 hystLowSignalOn; //NoSignal-to-LowSignal hysteresis level tFrac16 linearSignalLevelMax; //Level of the duty cycle for LinearSignal saturation tFrac16 linearSignalOutputMin; //Output at hystLowSignalOn tFrac16 linearSignalOutputMax; //Output at linearSignalLevelMax tFrac16 linearSignalSlope; // ((linearSignalOutputMax - linearSignalOutputMin)/(hystLowSignalOn - linearSignalLevelMax)))*2^(-linearSignalNshift) tFrac16 linearSignalOffset; // (linearSignalOutputMax - (linearSignalSlope * linearSignalLevelMax))*2^(-linearSignalNshift) tU16 linearSignalNshift; // scaling shift of the linear curve /* timing settings */ unsigned int minPeriod; //minimal period of the signal to be detected, shorter period leads to PWM_NoSignalDetect unsigned int maxPeriod; //maximal period of the signal to be detected, longer period leads to PWM_NoSignalDetect } pwmControlConfig_t;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ More details on the structures and values are described in the header file in attachment. There is a set of exported functions to be integrated into the application. /* Exported function headers */ extern void PWMControlInit(pwmControl_t * data); //Clears all the internal accumulators and prepars the algorithm for usage extern unsigned int PWMControlUpdate(unsigned int pin, pwmControl_t * data); //To be called within the timer input capture interrupt, updates the internal values and calculates the PWM frequency and duty-cycle extern tFrac16 PWMControlGetOutputValue(pwmControl_t * data); //To be called where necessary by the application to get the output value extern void PWMControlTimerOverflow(pwmControl_t * data);‍‍‍‍‍ //To be called within the timer overflow interrupt to indicate that the signal is lost‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Integration The PWM control source and header files should be included in the project to be compiled. The project uses NXP Automotive Math and Motor Control Library Set (AMMCLib version v1.1.17 or higher), which needs to be added to the project as well. For more information, please visit https://www.nxp.com/support/developer-resources/run-time-software/automotive-software-and-tools/automotive-math-and-motor-control-library-set:AUTOMATH_MCL?lang=en&lang_cd=en& The next step is to include the header file in the main application source code: #include "pwm_control.h"‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ In order to provide necessary settings and to handle the output, the following global variables are recommended: // PWM Control data pwmControl_t pwmControlData; //PWM input control data structure static tBool pwmControlEnabled = false; // Off by default‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Device initialization should include clock settings, timer, and input pin routing settings accordingly. For S12ZVML device, the configuration of TIM, PIM and LIN modules is following: Within the initialization part of the application, the following code should be placed to initialize the PWM control. Please consider the values as an example only.  // PWM control initial settings pwmControlData.config.minPeriod = 495; //Period of the max frequency pwmControlData.config.maxPeriod = 25641; //Period of the min frequency pwmControlData.config.noSignalLevel = FRAC16(0.05); //No signal detected below this duty cycle pwmControlData.config.noSignalOutput = FRAC16(0); //Output on ""no signal"" detected pwmControlData.config.lowSignalOutput = FRAC16(0); //Output on ""low signal"" detected pwmControlData.config.hystLowSignalOff = FRAC16(0.1); //Low level of the hysteresis. Smaller duty cycle means ""low signal"", higher duty cycle means ""switch on"" pwmControlData.config.hystLowSignalOn = FRAC16(0.15); //High level of the hysteresis. Smaller duty cycle means ""min speed or off"", higher duty cycle means ""switch on and linear"" pwmControlData.config.linearSignalLevelMax = FRAC16(0.85); //High level of the linear mode pwmControlData.config.linearSignalOutputMin = FRAC16(0.116666666666667); //Output within the hysteresis mode pwmControlData.config.linearSignalOutputMax = FRAC16(0.833333333333333); //Output at the linearSignalLevelMax pwmControlData.config.linearSignalSlope = FRAC16(0.511904761904762); //Linear signal slope = (linearSignalOutputMax - linearSignalOutputMin) / (linearSignalLevelMax - hystLowSignalOn) * 2^(-linearSignalNshift) pwmControlData.config.linearSignalOffset = FRAC16(-0.018452380952381); //Linear signal offset = (linearSignalOutputMin - (linearSignalOutputMax - linearSignalOutputMin) / (linearSignalLevelMax - hystLowSignalOn) * hystLowSignalOn) * 2^(-linearSignalNshift) pwmControlData.config.linearSignalNshift = 1; //Linear signal shift pwmControlData.config.f16pwmInputMA.u16NSamples = 5; //Moving average filter settings 2^n samples PWMControlInit(&pwmControlData);‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The configuration can be generated using an Excel sheet in the attachment. Content of the cell "D34" can be copied-pasted in the code. Name of the structure can be changed in "H1" cell. Orange-colored cells are customizable, while grey-colored cells use formulas to calculate output. Timer input capture interrupt routine should call the PWM control "Update" routine and switch the input capture mode between the rising edge and falling edge detection. In the case of S12ZVML device, the timer interrupt example follows: INTERRUPT void TIM0chan3_ISR(void) { // Read PWM input control pin and update status PWMControlUpdate(TIM0TC3, &pwmControlData); // Read the PWM Control output pwmControlData.outputValue = PWMControlGetOutputValue(&pwmControlData); // Toggle edge detection if(pwmControlData.flags.risingEdge) { TIM0TCTL4_EDG3A = 1; TIM0TCTL4_EDG3B = 0; } if(pwmControlData.flags.fallingEdge) { TIM0TCTL4_EDG3A = 0; TIM0TCTL4_EDG3B = 1; } // Clear interrupt flag TIM0TFLG1 = TIM0TFLG1_C3F_MASK; //TIM0TFLG1_C0F_MASK | TIM0TFLG1_C1F_MASK | TIM0TFLG1_C2F_MASK | TIM0TFLG1_C3F_MASK; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Timer overflow interrupt routine shall implement PWM control "Overflow" handler as follows (again, for S12ZVML device). Output value updater should be called as well to update the output value. INTERRUPT void TIM0overflow_ISR(void) { // Detect PWM input control period overflow (ultra low frequencies PWMControlTimerOverflow(&pwmControlData); pwmControlData.outputValue = PWMControlGetOutputValue(&pwmControlData); // Clear interrupt flag TIM0TFLG2 = TIM0TFLG2_TOF_MASK; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Finally, within the application task, the PWM control data can be accessed and used in the application. For example, based on the ControlInputClass, the input signal processing may be enabled or disabled and the output value can be used as the required speed value of an engine cooling fan. [Application Task] { // ... // PWM Control // If no signal is detected, enable manual switch (using FreeMASTER) if(pwmControlData.ControlInputClass == PWM_NoSignalDetect) { if(pwmControlEnabled == true) { cntrState.usrControl.switchAppOnOff = 0; pwmControlEnabled = false; } } else { pwmControlEnabled = true; } // If PWM input control enabled, update the demanded speed if(pwmControlEnabled) { //If the linear or high signal is detected, switch the app on if(pwmControlData.ControlInputClass >= PWM_LinearCtrlDetect) { cntrState.usrControl.switchAppOnOff = 1; //Store the demanded speed drvFOC.pospeControl.wRotElReq = pwmControlData.outputValue; } //else switch off the app... else { cntrState.usrControl.switchAppOnOff = 0; //...and if a fault is indicated, clear the fault if(cntrState.state == fault) { cntrState.usrControl.switchFaultClear = true; } } } // ... }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Example code Example code is provided for S12ZVML-MINIKIT. The code is a modified devkit SW, which is available here (and related AN5327 here). The FreeMASTER project file is included with added PWM Control subblock. If there is no PWM signal detected, the application can be controlled via FreeMASTER on/off button. If the PWM signal is detected (even with a duty-cycle below the minimal value), the application listens and reacts as defined by the signal definition. Conclusion PWM control is still being used as one of the control signals to control auxiliary electric drives in automotive. Even if being replaced by LIN or CAN communication, there are still facilities which can benefit from software drivers enabling such a feature. In this document, a software driver is provided to be integrated within the application. The example is provided for S12ZVML devices, however, it can be easily adopted to any device which meets the hardware requirements necessary for such PWM control signal detection.
View full article
Hello Community user, This post is intended to show how to recovery from Bus-Off state using the MSCAN and CANPHY modules in the MagniV devices. This example is focused on S12ZVC due to the internal CANPHY so it makes easier to create a quick example. What is Bus-Off condition? The bus-off condition is a catastrophic condition where the node in this state does not transmit anything on the bus. How to enter in Bus-Off state? A node enters in this state if any of the two error counters, Transmit Error Counter (TEC) and Receive Error Counter (REC) raises above 255. How to recovery from Bus-Off? A note is permitted to become error-active (no longer bus-off) when its error counters both set to 0 after 128 occurrences of 11 consecutive recessive bits have been monitored on the bus. The MSCAN module implements two ways to recover from the fault, the automatic and the manual. The automatic bus-off recovery method puts the node into the error-active state after monitoring 128 occurrences of 11 consecutive bits on the bus. It's important to note that the CANPHY also reports errors on the bus so, the proper error flags must be clear to assure the correct functionality of the node if CANPHY is being used. The manual bus-off recovery method (which is used in this example) puts the note into the error-active state after both independent events have become true in any order: 128 occurrences of 11 consecutive recessive bits on the CAN bus have been monitored. (Cannot be consecutive). CANMISC[BOHOLD] bit has been cleared by the user. Implementation The project contains a header file called  "common.h" which contains three defines that are used to set the CAN nodes. Just one define must be active per node. NODE0_TX and NODE1_TX are transmitting messages on the CAN bus and the NODE_RX is receiving the messages. #define NODE0_TX #define NODE1_TX #define NODE_RX‍‍‍‍‍‍ All nodes are blinking the green led indicating the communication is stable and no errors have occurred. At this point, you should generate the bus-off condition. A way to generate a bus-off condition is grounding one of the two CAN lines (CAN_High or CAN_Low) which will cause a bus-off condition to the transmitters nodes. When the node is in the bus-off state, the yellow led is toggled. At this point, you should not be any message being transmitted on the bus due to the transmitter node is in bus-off. The bus-off condition is detected by the application in the bus-off interrupt (refers Events.c file) which triggers the yellow led toggling. void CAN0_OnBusOff(void) { /* Get CAN bus status */ CAN0_GetError(&gCANErrpr); /* If bus error is set, inform to the application*/ if(gCANErrpr.errName.BusOff){ gBusOffState = PENDING; } CAN0RFLG_CSCIF = 1; // Clear flag }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ In the main.c file when the node transmitters are selected, there is a routine asking for a push-button event. This event triggers the bus-off recovery request by setting the CANMISC[BOHOLD]. At that point, the 128 occurrences of 11 consecutive recessive bits on the CAN bus should have passed and the green led will toggle again indicating the communication is stable again and no errors have occurred. At this point, you should see the messages on the CAN bus again. /* Read button to recovery from bus off condition*/ if(PushButton3_GetVal()){ CAN0_BusOffRecoveryRequest(); // Request get out of bus off gBusOffState = NONPENDING; /* Clear bus off LED indicator */ LED_YEL_OFF; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍ ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Note: The VLG-MC9S12ZVC was used for this example and the push button that must be pressed is SW12. Best Regards, Atzel Collazo
View full article
Example code pack for S12X contains simple code examples that show how to initialize and how to use MCU module/feature.   List of examples: S12XE_PLL - include S12XE_iPLL_Calculator XDP512 - ECT measuring of period - CW45 XDP512-CAN – pack of several example codes include CAN baud rate calculator XDT256 - ECT Pulse Width - CW47 XEP100 - ATD + GPIO - CW47 XEP100 - ATD and PIT - CW47 XEP100 - ATD Continuous conversion with interrupt - CW4 XEP100 - ATD multichannel - CW46 XEP100 - ATD Single conversion - CW46 XEP100 - CAN0 - CAN1 - CW45 XEP100 - ECT 500us interval - CW47 XEP100 - ECT 500us period - CW47 XEP100 - ECT as PWM - CW47 XEP100 - PWM 8bit - CW45 XEP100 - SCI default - CW47 XEP100-SCI_change_Baudrate-CW51 XEP100-SPI-CW51.ZIP XEP100-SPI-Master-Slave XS128 - PIT - CW47 XS128 - PIT 10ms+15ms and priority - CW47 XS128 - PWM 16bit - CW47     Note: More examples for S12XE could be downloaded here: LAMA's S12XE unofficial examples
View full article
Abstract The paper describes basic scaling procedure of a six-step BLDC motor control application with focus on S12ZVM MCU devices.  Abstract Introduction BLDC six-step control Speed scaling Timing Commutation periods Speed calculation Application note links Calculation accuracy Real applications Resources Introduction Based on the various questions regarding the BLDC speed calculation, I've decided to write this document to make the scale calculation clear. Please use it for your reference and comment in case there is something to be explained in more details. BLDC six-step control This document is linked with the six-step control of BLDC motors, known for the trapezoidal back-EMF shaped voltage. The key is to create a torque using DC current in two phases while the third phase is not connected. As the rotor is moving, the phases are switched (commutated) to keep the stator flux ahead the rotor flux. The principles are well described in many application notes, such as AN4718 or AN4704. The instant of the commutations can be driven by Hall sensors or by the back-EMF signal monitoring (so-called "sensorless"). For field-oriented control, please refer to the PMSM control discussed in AN5135 or AN5327. Speed scaling It's more benefitial to describe in details the sensorless algorithm over the hall-sensor-based control. However, the approach is almost the same. Timing The motor speed is calculated based on the zero-cross detection of BEMF voltage on a non-active phase. These zero-cross events times are measured by capturing a timer (TIM0CNT) register at the time the ADC routine detects a zero-cross (or when the Hall sensor commutation event occurs). That means, the time is scaled by the timer TIM0 settings. There is no general guidance how to set up the timer. However, the timer should be set to cover some reasonable number of ticks between two commutations (which is linked to the speed precission at high speeds) and should be able to cover two commutations "far away" from each other at very low speeds, without the timer overflow. A good practice would be: at least 100 timer ticks between two commutations maximum 16bit = 65535 ticks between two commutations The same aproach can be followed using the Hall-sensor events. Commutation periods In the application, zero-cross (or hall-sensor) periods are captured with periodZC_F_PhA, periodZC_R_PhA, etc. or periodZC[6], defined as tU16 (16 bit unsigned). The periods are captured using a timer, as mentioned above. In electric motor theory, we recognize "electrical" and "mechanical" speed. The "electrical" speed is linked with the rotational field. The mechanical speed is connected directly with the rotor speed. The relation between these two speeds is determined by number of poles or pole-pairs: (1)   mechanical speed = electrical speed / number of pole-pairs = electrical speed / ( number of poles / 2 ) In the following text, 3-phase BLDC motor is discussed. Speed calculation To calculate one "electrical" revolution of a motor = 6 commutations (or 6 zero-crosses), all the 6 commutation time periods shall be summed. For that case, the resulting "period6ZC" is defined, formated as tU32 (or unsigned long) to prevent an overflow if all six 16-bit zero-cross periods are summed. If you sum all the 6 zero-cross periods, you'll get the number of timer ticks per single "electric" revolution. That means, if the motor is 2-pole motor ( = 1 pole-pair motor), it would be the time per single "mechanical" revolution of the rotor. In thsi case: (2)   mechanical speed = electrical speed; You can easily get the time per mechanical revolution for higher-pole motor simply by multipling it by number of pole-pairs. (3)   time per mechanical revolution = period6ZC * number of pole-pairs  The period per 6 zero-crosses "period6ZC" is calculated within the control loop, usually in the 1 ms timer interrupt routine. Since the speed (rotor frequency) is just an inverted time period, we can use following code line to calculate the actualSpeed: (4) actualSpeed = SPEED_CALC_NUMERATOR / period6ZC; Now, how to read it's scale and what is the SPEED_CALC_NUMERATOR? Let's assume the "actualSpeed" is tFrac32 (1.31 formated signed 32bit number). It would mean the maximal fraction number is 1.0, which is represented by its integer value 2^31 = 2,147,483,648. Why to use 32-bit number over 16-bit is obvious - since the period6ZC is 32-bit value, the result should be of the same resolution or width. The task is to find the right SPEED_CALC_NUMERATOR. Let's consider the S12ZVM device and the timer TIM0 used to capture the zero-cross events times. The prescaler is set to 16 (TIM0TSCR2_PR = 4) and the bus clock is 12.5MHz, the timer tick is 12.5MHz / 16 = 781.25 kHz, in time scale it is 1.28us. Let's assume the maximum mechanical speed of the motor is 10,000 RPM and the motor has 6-pole-pairs. That would give us (5)   (10,000 RPM) / (60 seconds) = 166.67 revolutions per second, (6)   166.67*(6 pole-pairs) = 1000 electrical revolutions per second, so (7)   1000 * (6 commutations) = 6000 commutations/zero-crosses per second. (8)   That would make 1/6000 = 166.67us per one commutation. (9)   Ticks per one period at max speed = 166.67 us / 1.28us = 130.28 With our 1.28us timer, we can catch upto 130 periods at maximal speed. For maximal speed of the motor 10,000 RPM, we can simply rearrange the "actualSpeed" calulation shown in (4) into (13) and (14), assuming that: (10)   actualSpeed = FRAC32(1.0) = 2,147,483,648 (11)   period6ZC = 6 periods * 130 = 780 (rounded down, since the value is still an integer) In case of S12ZVM device, it is more convenient to use 16-bit (tFrac16) calculations than 32-bit. Hence, we can do a trick with the scaling to use 32-bit actualSpeed to prevent an overflow use the same 32-bit number as 16-bit number just by scaling it correctly benefit from the 16bit calculation, which is good enough and fast enough at the same time The trick is hidden in the casting of the actualSpeed from Frac32 to Frac16: (12)   speedErr = requiredSpeed - (tFrac16) actualSpeed; That means, only the lower 15 bits are considered the speed (assuming the actualSpeed will never exceed 32767 so the 16th "sign" bit will always be zero). For maximum speed and the SPEED_CALC_NUMERATOR determination, the "actualSpeed" should be 32767 (which is the range of signed tFrac16). Equation (4) can be used to calculate the SPEED_CALC_NUMERATOR as follows: (13)   32767 = SPEED_CALC_NUMERATOR / 780 (14)   SPEED_CALC_NUMERATOR  = 780 * 32,767 = 25,558,260 Thus  #define SPEED_CALC_NUMERATOR 25558260 Using the equation (4), the speed for the minimum period6ZC would be: (15)   actualSpeed = SPEED_CALC_NUMERATOR / period6ZC = 25,558,260 / 780 = 32,767; Masking that value by lower 15 bits and casting it to tFrac16 would give us 1.0. Since the speed scale has been determined by the maximum speed of the motor 10,000 RPM, we can calculate the real speed simply by: (16)   RealScaleSpeedRPM = (tFrac16)actualSpeed / 32,767 * MAX_SPEED = (tFrac16)actualSpeed / 32,767 * 10,000. Application note links In the application note AN4704, there are several macro constants used to control the application. These constants should be calculated using following definitions, with a little help of the SPEED_SCALE - floating point representation of the real scale of the speed. #define SPEED_SCALE 10000.0  // Used for correct calculation of the following: #define REQUIRED_RUN_SPEED FRAC16(2000.0/SPEED_SCALE) // 2000 rpm #define MIN_SPEED FRAC16(500.0/SPEED_SCALE) // 500 rpm minimal speed for Down button control (should be min 10% of nominal motor speed) #define MAX_SPEED FRAC16(5000.0/SPEED_SCALE) // 5 krpm maximum speed for Up button control #define SPEED_STEP FRAC16(100.0/SPEED_SCALE) // 100 rpm, Up/Down step for button controls   If the application uses FreeMASTER to display or control, the scales shall be updated in the FreeMASTER project as well. The new FM scales for AN4704 are: Variable name Variable watch settings requiredSpeed Real type transformation: Linear: a = SPEED_SCALE = 10,000; b = 0 actualSpeed Signed int, Size = 4 Show as: REAL Bit fields maks with: word (0xffff) Real type transformation: Linear: a = SPEED_SCALE / 32767.0 = 0.3051851; b = 0  Calculation accuracy Now, let's have a look on the speed resolution (or accuracy): At the full speed, if one period changes by 1 tick, then you'll get the period6ZC from 780 to 781 at max speed, which makes 12.8041 RPM difference. The higher the SPEED_SCALE is, the higher the error is. If the assumption would be a change in all of the 6 periods (thus the period6ZC would change from 780 to 786), the resulting change to the speed would be 76.336 RPM. That makes the speed error 10,000 RPM +- 76, which is 0.76%. In terms of accuracy, it makes sense to set the maximum speed (or the SPEED_SCALE) to the maximal speed of the application instead of copying some high number from the datasheet of the motor. Well, the max speed of the application should not exceed the max speed of the motor, but it doesn't help if the speed scale is unnecessarily high. Real applications In real applications, the calculated speed (actualSpeed) reflects all the deviations and changes of the period6ZC. Therefore, it is a good practice to do some kind of filtering of the period6ZC, either by averaging or using a low-pass filter. In case of one or more zero-crosses are lost, there should a mechanism to process and detect if the motor is stalled (mechanical speed loses lock with the commutation) or if it is just a disturbance to the signal. The stall detection or the Hall-signal fault/damage detection is one of the challenges towards high quality application. Resources S12ZVM MCU - NXP main S12ZVM page AutoMCDevKits - NXP Automotive Motor Control Development Solutions AN4718 - 3-Phase BLDC Hall Sensor Application Using S12ZVM AN4704 - 3-phase Sensorless BLDC Motor Control Kit with the S12 MagniV MC9S12ZVM AN5201 - Integrating the LIN driver with BLDC sensorless motor controller In the S12ZVM128 device AN5330 - Migration Guide for S12ZVM Devices
View full article
Example code pack for S12G contains simple code examples how to initialize and how to use MCU module/feature. List of examples: G128-API_wakeup_from_Stop_Mode G128-Clock and COP examples G128-Interrupt_catcher-CW51 G128-LIN-CW51 G128-PLL_PEEmode-CW51 G128-Security-CW51 G240-API+STOP-CW51 G240-API-CW51 G240-ATD+GPIO-CW51 G240-ATD-Continuous_conversion_with_interrupt-CW51 G240-ATD-Multichannel_single_conversion-CW51 G240-ATD-Single_conversion-CW51 G240-Checksum-CW51 G240-Flash-CW51 G240-PLL-PBE_mode-CW51 G240-PLL-PEE_mode-CW51 G240-PLL-PEI_mode-CW51 G240-TIM_50us_interval-CW51 G240-TIM_50us_period-CW51 GN32-EEPROM-EW-CW51 GN32-LIN-CW51 GN32-PWM16b_GPIO GN32-PWM_8bit-CW51 GN32-SCI_SPI_Gateway-CW51 GN32-SCI_wake_up_from_stop-CW51   Oct-22-2013 Update: I added G128-CAN-CW51, G240-SPI-MC33810-CW51, G240-SPI-Slave examples. I added PLL calculator. I fixed error in GN32-EEPROM-EW-CW51 example code.   Aug-21-2015 Update: Updated G240-Flash-CW51 example code. Removed image files and object code from projects (9MB->2MB size)
View full article
Since there isn't a CAN based bootloader developed for S12X device family, here are some useful documents that might be of help for creating such bootloader:   - The AN3312 is an application note of a BootLoader that uses CAN but it is targetted for our DSC family of devices. These devices have the FlexCAN module (the silicon that handles CAN Communications is different to the one in the MC9S08DZ60). However this document can be used as a reference on how to build a loader. https://www.nxp.com/docs/en/application-note/AN3312.pdf    - Following document explains how to use the msCAN module for communications. It provides basic examples on how to send and receive data through the port. https://www.nxp.com/docs/en/application-note/AN3034.pdf    - Next document provides the source code and documentation for an assembly-written Bootloader. This software loads the code through the serial port and burns it into flash. This document can help you understand the specific details of the bootloader implementation. This code is available for a lot of S08 families included the MC9S08DZ60 device. https://www.nxp.com/docs/en/application-note/AN2295.pdf  - Serial booloader for S12(X) family: https://www.nxp.com/docs/en/application-note/AN4258.pdf    With the information in these documents you can design your loader and plan how to solve the 5 main challenges of a loader application:   ++Memory Protection++ The Boot Loader handles the non-volatile memory of the microcontroller. The developer must plan how much memory is needed for the loader and protect it. Memory protection provides a guideline of the final system memory organization. A section of memory is used for the loader and another section for the application. Applications that will be executed with a loader are affected by how the loader manages memory and interrupt vectors.   ++Burning Flash++ Programming and Erasing non-volatile memory requires special attention as the procedure must be executed in RAM. The process of handling NVM may vary between devices. We have source code that provides routines to write Flash and that solves the problem of executing in RAM.   ++Vector Redirection+ Interrupt vectors should be shared between the application and the users code. Hardware vector redirection is supported by the microcontrollers but with some limitations. It is necessary to decide how vector redirection will be implemented. Software and hardware methods can be used to redirect vectors.   ++Data Interface++ Different applications required different interfaces to receive s-record information. Serial Ports are used widely for this purpose although the bootloader implementation should allow exchanging interfaces in a simple way. For your case you want CAN interface. CAN frames support up to 8 bytes of data per frame. This requires the developer to fully design a protocol or a data structure mounted over the CAN frames to be able to send the complete frames to the device that will be reprogrammed.   ++Mode Selection++ The Boot Loader is the owner of the reset vector. Upon startup the Boot Loader should select if the User code will be executed or if the Boot Loader mode should execute. The applicaton determines the best way to select between User/Loader mode. It might be a simple GPIO or a CAN frame or any input that can be recognized by the application and Loader to be able to set the loader mode when needed. Developing a loader is not easy, but hopefully this information will be of a great help.
View full article
The S12Z MCU has linear address space therefore constant, variable, code placement is easier in compare with older S12 or S12X MCUs. But still, there are several ways and potential issues.   The object placement is made by Smart Linker. The linker configuration is defined by settings in project *.prm file and also by linker command line options (menu - Project – Properties – C/C++ Build – Settings – S12Z Linker). The detail information about linker options may be found in MCU_Build_Tools_Utilities.pdf with default path: "c:\Freescale\CW MCU v10.7\MCU\Help\PDF\MCU_Build_Tools_Utilities.pdf"   We may define memory segments in *.prm linker file. The default prm file contains segments for RAM, EEPROM, and ROM (Flash). The sizes of these segments typically reflect our MCU derivative physical memory map, but we may redefine that and use more virtual segments per our needs. The physical/virtual segments definition in prm linker file is located at: SEGMENTS // segments definition END‍‍‍‍‍‍   The general data placement may be divided into two main approaches: Manual – the programmer will specify fix address for some of the data Automatic – the placement will be driven automatically by Smart Linker   Manual placement The first option is an exact specification of specific content at a specific address. This may be managed for a small amount of data by FILL linker command in *.prm linker parameter file. For example: SEGMENTS //… ROM_CONST       = READ_ONLY   0xFE0000 TO 0xFE0000 FILL 0x5A;  //insert 0x5A value at address 0xFE0000 //… END‍‍‍‍‍‍‍‍‍‍ Such placement isn’t very comfortable, but it might be simply used for some configuration data out of project code. Note: you may use more than one bytes (e.g. FILL 0x0A 0x34). If segment size is bigger than a number of specified bytes, the bytes will be used as a pattern for filling whole target segment. Note: The potential linker placement will overlap such defined data.   The next option is using address specification by an @ qualifier directly in C code. For example: unsigned const int rom_const @0xFE0100 = 0x5AA5;‍‍ This may be used also for more complex types than simple byte – typically arrays,...   Since such type of placement is still manual, the linker parameters must be configured for avoiding possible overlapping. Be aware! The default CW project has disabled memory overlapping warnings. So, we must exclude target memory area from linker using. For example, in the *.prm file: SEGMENTS //… ROM_1           = READ_ONLY   0xFE0000 TO 0xFE00FF //ROM_CONST  = READ_ONLY   0xFE0100 TO 0xFE0101;            //we use the 0xFE0100 byte for rom_const ROM_2           = READ_ONLY   0xFE0102 TO 0xFFFDFF //… END‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Note: We use qualifiers for define memory access type. READ_ONLY is used for Flash, READ_WRITE for RAM and NO_INIT for RAM where we do not want to initialize data after reset. Sections placed in an NO_INIT segment should not contain any initialized variables (variable defined as int c = 8).   Note: The manual placement may be also implemented by assembler code. For example: XDEF MyVariable MyVariable: equ $1100‍‍‍‍ However, also in this case, we must exclude target memory area from linker use like in the case of @ qualifier for avoiding memory overlapping.   Automatic placement by linker The PLACEMENT block allows us to physically place each section from the application in a specific memory area (segment). The sections specified in a PLACEMENT block may be linker-predefined sections (like DEFAULT_ROM, DEFAULT_RAM, COPY, SSTACK,…) or user sections specified in one of the source file building the application (like MY_RAM,…). PLACEMENT // section(s) INTO segment(s); MY_CODE INTO ROM_1; END‍‍‍‍‍‍‍‍ Note: Since the linker is case sensitive, the name of the section names specified in the PLACEMENT block must be valid predefined or user-defined section names. Note: There is quite mess in ELF/Freescale section/segment terminology. Please take this information as simplified as possible. Please look at MCU_Build_Tools_Utilities.pdf for more details about predefined segments/sections. Note: We may place a various number of sections into a various number of segments. The “,” is used as section/segment delimiter. Note: In general, the placement order is given by simple list order (first specified section will be allocated from first specified segment, after that next section …). But, there are still few limitations for sections list order. The error is generated in the case of wrong list order – for example: ERROR L1122: only checksum section may be behind .copy in the section list.   The default variable/constant/code placement may be changed by #pragma commands. Note: Most of these pragma commands are not limited to the single file. Therefore, we should keep it in complementary pairs. An example of placing code into specific section: #pragma CODE_SEG MY_CODE void f(void) { //… } #pragma CODE_SEG DEFAULT‍‍‍‍‍‍‍‍‍‍‍‍ The #pragma DATA_SEG modifies variable placement. For example: #pragma DATA_SEG MY_RAM unsigned int counter; //… #pragma DATA_SEG DEFAULT‍‍‍‍‍‍‍‍   The #pragma CONT_SEG modifies variable placement. For example: #pragma CONT_SEG MY_ROM const unsigned int my_parameter; //… #pragma CONT_SEG DEFAULT‍‍‍‍‍‍‍‍   Note: The shorter option for directly allocating variables in a named segment, rather than using a #pragma may be used. For example: unsigned int counter@"MY_RAM";‍‍ However, even in such case, the #pragma command like #pragma DATA_SEG MY_RAM must be used at least once prior that variable declaration.   Note: The S12Z compiler/linker allows to use also already predefined sections like DEFAULT_ROM, DEFAULT_RAM or ROM_VAR as target sections in #pragma commands (not possible in the case of older S12(X) compiler/linker).     More details about #pragma commands may be found in MCU_S12Z_Compiler.pdf with default path: "c:\Freescale\CW MCU v10.7\MCU\Help\PDF\MCU_S12Z_Compiler.pdf" Data alignment Sometimes we need to keep allocated data aligned. This is for example typical requirement for ADC command and result list where DMA is used for transfer data between ADC module and memory. The simplest method is using alignment attribute. For example: volatile unsigned long adc0_cmdlist[NR_A_CH] __attribute__ ((aligned (4))); //max 256 bytes = 64 commands per 4-byte entries volatile unsigned int adc0_results[NR_A_CH] __attribute__ ((aligned (4)));  //max 128 bytes = 64 results per 2-byte entries‍‍‍‍ I hope it helps you. Best regards Radek
View full article
The example code demonstrates MCU low power modes: STOP and WAIT. For detailed description see main.c file of the project. * - tested on X-VLG-S12ZVC board * - BUSCLK = 6.25MHz based on internal oscillator clock IRCCLK = 1MHz.The PLL set by default in PEI mode. * - Reference documentation: MC9S12ZVCRMV1.pdf (REV 1.9) VLG-MC9S12ZVC-SCH.pdf (Document Number SCH-28038, SPF-28038)
View full article
Interrupt catcher example code catches all unexpected interrupts. It can be used for debugging or directly in the application software. The Machine Exception routine is used here as example of expected interrupt.   A few notes: 1. For each expected interrupt you must remove a code line for given interrupt     from the part of the code "A Set of unimplemented interrupts" and     create your own service routine as it is, for example, made     for interrupt 5 void Machine_Exception_ISR(void)   2. All interrupt vectors have 32bit size, however, addresses have only 24bit,     therefore the most significant byte in interrupt vector is not used.     Definitions with the keyword "interrupt XX" where XX represents vector     order in the interrupt vector is used to define interrupt service function.      3. Interrupt number 0 is assigned to POR reset vector,                      1 is assigned to Unimplemented page1 op-code trap vector                      2 is assigned to Unimplemented page2 op-code trap vector                      3  ...                      4  ...     Interrupt number = (0x1FC-Vector Address)/4. See Table 1-11. Interrupt     Vector Locations at RM(page 62-65).     For Example: Interrupt number of SCI0 = (0x1FC-0x19C)/4 = 0x18 = 24.     So you can use either form                interrupt VectorNumber_Vsci0 void SCI0_isr(void)     or                interrupt 24 void SCI0_isr(void)     or                interrupt ((0x1FC-0x19C)/4) void SCI0_isr(void)       Note: VectorNumber_Vsci0 is defined in mc9s12zvl32.h      
View full article
The example demonstrates the COP watchdog reset on MC9S12ZVL32 microcontroller. The code can be used on any MagniV device based on S12Z core. The example project is created in CodeWarrior v10.6 (Eclipse IDE). The SW code has been tested on TRK-S12ZVL board.   * Brief description: The Phase Locked Loop (PLL) is set by default to PEI mode, so the bus clock is 6.25MHz based on 1MHz internal RC oscillator (IRC1M). The RGB LED (red) is used to indicate MCU runs after reset. When the RGB colour changes to green, the COP time-out period has started. After the period times out, the COP generates a reset and COPRF flag is set. After the reset, based on COPRF flag, the Blue LED is turned on indicating previous reset has been generated by COP watchdog. The COP time-out period is set to maximum (CPMUCOP register, bits CR[2:0]=7). The number of COPCLK cycles to time-out is 2^24 = 16777216. The COPCLK is based on IRCCLK (by default) with 1MHz clock frequency. The maximum COP time-out period in this case is approximately 16.78 seconds. - On the TRK-S12ZVL board:   Port P is used to drive RGB LED. Anode is connected to VDDX, a cathode to port  pin. Port P can be set as output (DDRP=0xFF) and logic zero on output enables LED.   - Reference documentation: MC9S12ZVL Family Reference Manual & Datasheet TRK-S12ZVL Board schematics
View full article
A project presents control of the HD44780 driven display where it is assumed that RW pin of the LCD is permanently connected to “Write” level (GND). The SW contains mirror(s) of the LCD display as array of characters stored within RAM. Both read and write function can be used because writing is performed to the display and also to the array. Read functions are directed to the character array stored within RAM.
View full article
In the attached zip file you can find three software examples demonstrating clock module and PLL configuration on MagniV device MC9S12ZVM. The examples are made in CodeWarrior IDE v10.6 (Eclipse). The main.c source file of each project provides detailed description, comments and important notes.   The source code can be used with other devices within MagniV family based on S12Z core such as S12ZVL, S12ZVC, S12ZVH/Y, but the precaution must be considered about the max bus frequency of the device.   p.s. Revision 2: SYNR, REFDIV and POSTDIV values changed in PLL initialization to achieve highest PLL locking time.
View full article
Here is the example code demonstrating erase/write/read of internal EEPROM module integrated into MagniV devices such as S12ZVM, S12ZVC, S12ZVL etc.   Find detailed description in the project's main.c file.   The example project was created in CodeWarrior IDE v10.6.4 and tested on TRK-S12ZVL board.
View full article
How to get device ID and write program once field without programming application to the S12Z device in the CodeWarrior (Eclipse).   Even the datasheet does not present the device ID it can be read at address 0x1FC000. The device ID is size of 8 bytes from 1F_C000 to 1F_C007. The meaning of the field is confidential information. Of course, other "reserved" fields on higher addresses can also be read but their meaning is also confidential. The ID is not presented in the documentation because it has reason for company only. However, some users require unique identification of the device. It is possible to use this number. In order to read the ID, it is enough to create simple project in the CodeWarrior and connect to the device without programming it and run “mem” command in the debug shell window. If you do not want to remember address ranges, then it is better to prepare command file and execute it.   Of course, we can also simply use memory window.   It is a different story if we want also to see program once field. In this case we have to execute a set of commands to get it. As an example of command file which can be executed to get device ID and program the program once field I present two command files. They can be executed in the debugger window – see and test attached project. They are AAA_Read_Device_ID_And_OTPROM.cmd  and AAA_ProgramOnceField.cmd. The project which also presents reading and writing program once field is not relevant but should be created for the device we want to play with. It is not required to be code (simple code, enough to use what is generated by wizard) loaded into the MCU’s memory. However, necessary is the debugger is connected to a memory. Because of this it is enough to set:   …. And press debug   In the debug enable “Debugger Shell”:   Before continuing please modify flash clock setup in both files to value suitable for programming on the basis of the oscclk you use. In the files search for lines    Write into debugger shell command which runs the AAA_Read_Device_ID_And_OTPROM.cmd: source "c:\D\CODING & SW\ECLIPSE\S12ZVMC-FLASH-WRITEONCEFIELD-CW106\AAA_Read_Device_ID_And_OTPROM.cmd" (it is possible you have different path to the file…please change it)   The command will execute and shows: Device ID And Program field phrase 0. If you want to see another phrase you should modify AAA_Read_Device_ID_And_OTPROM.cmd line set PHRASE 1. Change 1 to the phrase you want to see and run the command presented above “source …..” again. It is enough to press arrow up on the keyboard to see and use previous commands.   In order to program selected field use and run command “source” with the file: AAA_ProgramOnceField.cmd source "c:\D\CODING & SW\ECLIPSE\S12ZVMC-FLASH-WRITEONCEFIELD-CW106\AAA_ProgramOnceField.cmd"   The same note as previosly, the path you have could be different so adjust it. The same line as in previous file should be changed to select the phrase you want to program. As a result, you will see programming algorithm and also read back of the field, example of output: %>source "c:\D\CODING & SW\ECLIPSE\S12ZVMC-FLASH-WRITEONC EFIELD-CW106\AAA_ProgramOnceField .cmd" ############################ Programming Field = 2 ############################ cmdwin::mem 0x0386 %x = 0x30 cmdwin::wait 1000 cmdwin::mem 0x0382 %x = 0x05 cmdwin::mem 0x038C %x = 0x07 cmdwin::mem 0x038D %x = 0x00 cmdwin::mem 0x038E %x = 0x00 cmdwin::mem 0x038F %x = 2 cmdwin::mem 0x0390 %x = 0xA2 cmdwin::mem 0x0391 %x = 0xB2 cmdwin::mem 0x0392 %x = 0xC2 cmdwin::mem 0x0393 %x = 0xD2 cmdwin::mem 0x0394 %x = 0xE2 cmdwin::mem 0x0395 %x = 0xF2 cmdwin::mem 0x0396 %x = 0xA3 cmdwin::mem 0x0397 %x = 0xB3 cmdwin::mem 0x0386 %x = 0x80 cmdwin::wait 1000 ############################ Read back Programmed Field = 2 ############################ cmdwin::mem 0x0386 %x = 0x30 cmdwin::wait 1000 cmdwin::mem 0x0382 %x = 0x01 cmdwin::mem 0x038C %x = 0x04 cmdwin::mem 0x038D %x = 0x00 cmdwin::mem 0x038E %x = 0x00 cmdwin::mem 0x038F %x = 2 cmdwin::mem 0x0386 %x = 0x80 cmdwin::wait 1000 cmdwin::mem 0x0390 8      390  $a2 $b2 $c2 $d2 $e2 $f2  $a3 $b3   . . . . . . . .    Now the question, where to find commands to be able to prepare such a command files, can be asked. 1) The first information source is the CodeWarrior help. For example, search for keyword DW and it could find a command list. 2) Tcl Reference Manual  3) http://www.tcl.tk/    Finally, in the attached project can be seen also approach how to write program once field by SW. Of course, mentioned cmd files are also part of the project.
View full article
S12 FAMILY DEVICES COP RECOGNITION CONSIDERATIONS SHOULD HELP YOU TO SET HW OF THE RESET PIN TO BE COP CORRECTLY RECOGNIZED The calculator can be found at S12 FAMILY DEVICES COP RECOGNITION CONSIDERATIONS - calculator.xlsx
View full article
Hello all, sharing the latest version of MagniV Power Dissipation Calculator started by Carlos Vazquez and Anita Maliverney. With this excel sheet is possible estimate the power dissipated for any MCU of S12ZVM, S12ZVL, S12ZC family, considering: supply voltages, digital modules, gate drive unit, charge pump, communication transceivers, etc.   A few features where added, any additional comment or suggestion is appreciated. Regards.
View full article
Here is the example code demonstrating erase/write/read of internal Flash module integrated into MagniV devices such as S12ZVM, S12ZVC, S12ZVL etc.   Find detailed description in the project's main.c file.   The example project was created in CodeWarrior IDE v10.6.4 and tested on TRK-S12ZVL board.
View full article