概要
dsPIC33Cシリーズの高分解能PWMモジュールは様々なスイッチングアプリケーションに対応できる構成となっています。
今回はコンビネーションロジック機能を試してみます。
簡単にコンビネーションロジックの機能を説明しますと、各PWMの出力をロジック回路(Not,And,Or,Xor)を介し他のPWM出力にアサインする機能です。

ハードウェア構成と制御ブロック
今回のプログラムはPWM1に1MHz、PWM2に100kHz、PWM3HにPWM1H And PWM2H、PWM3LにPWM1L And PWM2Lを出力してみます。


レジスタ
関連レジスタに関しては非常に多いため、今回の動作に関係する部分だけ抜粋します。
| レジスタ名 | 機能 | 説明 |
| PCLKCON | PWM CLOCK CONTROL REGISTER | PWMクロックを制御 |
| PGxCONL | GENERATOR x CONTROL REGISTER LOW | PGxのクロックや動作モードの設定を行います |
| PGxIOCONH | PWM GENERATOR x I/O CONTROL REGISTER LOW | PGxの出力ピンに関する設定を行います |
| PGxPER | PWM GENERATOR x PERIOD REGISTER | PGxの周期を設定します |
| PGxPHASE | PWM GENERATOR x PHASE REGISTER | PGxの位相を設定します |
| PGxDC | PWM GENERATOR x DUTY CYCLE REGISTER | PGxのデューティを設定します |
| PGxDTH PGxDTL | PWM GENERATOR x DEAD-TIME REGISTER | PGxのデッドタイムを設定します |
| LOGCON | Combinatorial PWM Logic Control Register | コンビネーションロジックに関する設定を行います |
ソースコード
コードに関しては以下の部分がコンビネーションロジックの動作を決定する部分です
/* 組み合わせPWMロジック出力先選択ビット */
LOGCONAbits.PWMLFAD = PWM_DRV_LOGCON_DISTINATION_ACE_PWM3H;
/* 組み合わせPWMロジック機能選択ビット(1 = AND) */
LOGCONAbits.PWMLFA = PWM_DRV_LOGCON_FUNCTION_AND;
/* PWMコンビネーションロジックAソース2極性ビット */
LOGCONAbits.S2APOL = PWM_DRV_LOGCON_SOURCE_POL_NORMAL;
/* PWMコンビネーションロジックAソース1極性ビット */
LOGCONAbits.S1APOL = PWM_DRV_LOGCON_SOURCE_POL_NORMAL;
/* PWMコンビネーションロジックAソース2選択ビット */
LOGCONAbits.PWMS2A = PWM_DRV_LOGCON_SOURCE_PWM2H;
/* PWMコンビネーションロジックAソース1選択ビット */
LOGCONAbits.PWMS1A = PWM_DRV_LOGCON_SOURCE_PWM1H;
/* コンビネーションPWMロジックA分配ビット */
LOGCONBbits.PWMLFBD = PWM_DRV_LOGCON_DISTINATION_BDF_PWM3L;
/* コンビネーションPWMロジックB機能ビット */
LOGCONBbits.PWMLFB = PWM_DRV_LOGCON_FUNCTION_AND;
/* PWMコンビネーションロジックBソース2極性ビット */
LOGCONBbits.S2BPOL = PWM_DRV_LOGCON_SOURCE_POL_NORMAL;
/* PWMコンビネーションロジックBソース1極性ビット */
LOGCONBbits.S1BPOL = PWM_DRV_LOGCON_SOURCE_POL_NORMAL;
/* PWMコンビネーションロジックAソース2選択ビット */
LOGCONBbits.PWMS2B = PWM_DRV_LOGCON_SOURCE_PWM2L;
/* PWMコンビネーションロジックAソース1選択ビット */
LOGCONBbits.PWMS1B = PWM_DRV_LOGCON_SOURCE_PWM1L;
コンフィグレーション設定についてはコンフィグレーション設定に記載しております。
コピーして下記のソースコードの「 //ここにコンフィグレーション設定を挿入する// 」の位置に挿入してください。
クロック設定用関数 vds_Main_Init_Clock_Register(); のソースコードはクロック設定のページに記載しております。
コピーして下記のソースコードの「 //ここにクロック設定ソースをコピペする// 」の位置に挿入してください。
/*----------------------------------------------------------------------------*/
/* <Chapter> CHAPTER_2_7_4_HRPWM_CMB */
/* <Function> PWM2,PWM3のPWM信号(100kHz) をPWM1のPWM信号(1MHz)でチョッピング */
/* <Peripharal> PWM関連 */
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/* コンフィグレーション設定*/
/*----------------------------------------------------------------------------*/
//ここにコンフィグレーション設定を挿入する//
/*----------------------------------------------------------------------------*/
/* インクルードファイル*/
/*----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
/*----------------------------------------------------------------------------*/
/* 定数定義*/
/*----------------------------------------------------------------------------*/
#define PWM_DRV_LOGCON_SOURCE_PWM1H ( 0u )
#define PWM_DRV_LOGCON_SOURCE_PWM1L ( 1u )
#define PWM_DRV_LOGCON_SOURCE_PWM2H ( 2u )
#define PWM_DRV_LOGCON_SOURCE_PWM2L ( 3u )
#define PWM_DRV_LOGCON_SOURCE_PWM3H ( 4u )
#define PWM_DRV_LOGCON_SOURCE_PWM3L ( 5u )
#define PWM_DRV_LOGCON_SOURCE_PWM4H ( 6u )
#define PWM_DRV_LOGCON_SOURCE_PWM4L ( 7u )
#define PWM_DRV_LOGCON_SOURCE_PWM5H ( 8u )
#define PWM_DRV_LOGCON_SOURCE_PWM5L ( 9u )
#define PWM_DRV_LOGCON_SOURCE_PWM6H ( 10u )
#define PWM_DRV_LOGCON_SOURCE_PWM6L ( 11u )
#define PWM_DRV_LOGCON_SOURCE_PWM7H ( 12u )
#define PWM_DRV_LOGCON_SOURCE_PWM7L ( 13u )
#define PWM_DRV_LOGCON_SOURCE_PWM8H ( 14u )
#define PWM_DRV_LOGCON_SOURCE_PWM8L ( 15u )
#define PWM_DRV_LOGCON_SOURCE_POL_NORMAL ( 0u )
#define PWM_DRV_LOGCON_SOURCE_POL_INVERT ( 1u )
#define PWM_DRV_LOGCON_FUNCTION_OR ( 0u )
#define PWM_DRV_LOGCON_FUNCTION_AND ( 1u )
#define PWM_DRV_LOGCON_FUNCTION_EXOR ( 2u )
#define PWM_DRV_LOGCON_DISTINATION_ACE_DISABLE ( 0u )
#define PWM_DRV_LOGCON_DISTINATION_ACE_PWM2H ( 1u )
#define PWM_DRV_LOGCON_DISTINATION_ACE_PWM3H ( 2u )
#define PWM_DRV_LOGCON_DISTINATION_ACE_PWM4H ( 3u )
#define PWM_DRV_LOGCON_DISTINATION_ACE_PWM5H ( 4u )
#define PWM_DRV_LOGCON_DISTINATION_ACE_PWM6H ( 5u )
#define PWM_DRV_LOGCON_DISTINATION_ACE_PWM7H ( 6u )
#define PWM_DRV_LOGCON_DISTINATION_ACE_PWM8H ( 7u )
#define PWM_DRV_LOGCON_DISTINATION_BDF_DISABLE ( 0u )
#define PWM_DRV_LOGCON_DISTINATION_BDF_PWM2L ( 1u )
#define PWM_DRV_LOGCON_DISTINATION_BDF_PWM3L ( 2u )
#define PWM_DRV_LOGCON_DISTINATION_BDF_PWM4L ( 3u )
#define PWM_DRV_LOGCON_DISTINATION_BDF_PWM5L ( 4u )
#define PWM_DRV_LOGCON_DISTINATION_BDF_PWM6L ( 5u )
#define PWM_DRV_LOGCON_DISTINATION_BDF_PWM7L ( 6u )
#define PWM_DRV_LOGCON_DISTINATION_BDF_PWM8L ( 7u )
/*----------------------------------------------------------------------------*/
/* 変数定義*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/* クロック設定 */
/*----------------------------------------------------------------------------*/
//ここにクロック設定ソースを挿入する//
/*----------------------------------------------------------------------------*/
/* Main関数 */
/*----------------------------------------------------------------------------*/
int main(int argc, char** argv)
{
/*------------------------------------------------------------------------*/
/* クロック初期化*/
/*------------------------------------------------------------------------*/
vds_Main_Init_Clock_Register(); /* クロック初期化 */
/*------------------------------------------------------------------------*/
/* GPIO初期化*/
/*------------------------------------------------------------------------*/
TRISEbits.TRISE0 = 0u; /* LED1ピンはデジタル出力ピン */
ANSELAbits.ANSELA0 = 1u; /* RA0ピンはアナログピン(ポテンション入力)*/
/*------------------------------------------------------------------------*/
/* PWM初期化*/
/*------------------------------------------------------------------------*/
PG1CONLbits.ON = 0u;
PG2CONLbits.ON = 0u;
PG3CONLbits.ON = 0u;
/*------------------------------------------------------------------------*/
/* PWMクロックの設定*/
/*------------------------------------------------------------------------*/
PCLKCONbits.MCLKSEL = 3u; /* Auxiliary PLL post-divider output*/
/*------------------------------------------------------------------------*/
/* PGx制御レジスタLの設定*/
/* 周期はマスターピリオドレジスタ(MPER)を使用*/
/*------------------------------------------------------------------------*/
PG1CONLbits.CLKSEL = 1u;
PG1CONLbits.MODSEL = 0u;
PG2CONLbits.CLKSEL = 1u;
PG2CONLbits.MODSEL = 0u;
PG3CONLbits.CLKSEL = 1u;
PG3CONLbits.MODSEL = u;
/*------------------------------------------------------------------------*/
/* PGx制御レジスタHの設定*/
/* 周期はマスターピリオドレジスタ(MPER)を使用*/
/*------------------------------------------------------------------------*/
PG2CONH = 0x4000;
PG3CONH = 0x4000;
PG1CONH = 0x0000;
/*------------------------------------------------------------------------*/
/* PGxIOレジスタHの設定*/
/* PWMジェネレータがピンを使用する*/
/*------------------------------------------------------------------------*/
PG2IOCONH = 0x000C;
PG3IOCONH = 0x000C;
PG1IOCONH = 0x000C;
/*------------------------------------------------------------------------*/
/* PGxIOレジスタLの設定*/
/* PCI電流リミットが発生した時にCLDATの値を使用*/
/* CLDAT = PWMxHがLow,PWMxLがHigh*/
/*------------------------------------------------------------------------*/
PG2IOCONL = 0x0010;
PG3IOCONL = 0x0010;
PG1IOCONL = 0x0010;
/*------------------------------------------------------------------------*/
/* 周期/Duty/フェーズの設定*/
/*------------------------------------------------------------------------*/
MPER = 5000; /* 周期レジスタ */
PG2DC = MPER >> 1u; /* PG2 Dutyレジスタ*/
PG2PHASE = 0;
PG3DC = MPER >> 1u; /* PG3 Dutyレジスタ*/
PG3PHASE = 0;
PG1PER = 500;
PG1DC = PG1PER >> 1u; /* PG3 Dutyレジスタ*/
PG1PHASE = 0;
/*------------------------------------------------------------------------*/
/* デッドタイムの設定*/
/*------------------------------------------------------------------------*/
PG2DTH = 100;
PG2DTL = 100;
PG3DTH = 100;
PG3DTL = 100;
PG1DTH = 10;
PG1DTL = 10;
/*------------------------------------------------------------------------*/
/* コンビネーションロジックの設定*/
/*------------------------------------------------------------------------*/
/* 組み合わせPWMロジック出力先選択ビット */
LOGCONAbits.PWMLFAD = PWM_DRV_LOGCON_DISTINATION_ACE_PWM3H;
/* 組み合わせPWMロジック機能選択ビット(1 = AND) */
LOGCONAbits.PWMLFA = PWM_DRV_LOGCON_FUNCTION_AND;
/* PWMコンビネーションロジックAソース2極性ビット */
LOGCONAbits.S2APOL = PWM_DRV_LOGCON_SOURCE_POL_NORMAL;
/* PWMコンビネーションロジックAソース1極性ビット */
LOGCONAbits.S1APOL = PWM_DRV_LOGCON_SOURCE_POL_NORMAL;
/* PWMコンビネーションロジックAソース2選択ビット */
LOGCONAbits.PWMS2A = PWM_DRV_LOGCON_SOURCE_PWM2H;
/* PWMコンビネーションロジックAソース1選択ビット */
LOGCONAbits.PWMS1A = PWM_DRV_LOGCON_SOURCE_PWM1H;
/* コンビネーションPWMロジックA分配ビット */
LOGCONBbits.PWMLFBD = PWM_DRV_LOGCON_DISTINATION_BDF_PWM3L;
/* コンビネーションPWMロジックB機能ビット */
LOGCONBbits.PWMLFB = PWM_DRV_LOGCON_FUNCTION_AND;
/* PWMコンビネーションロジックBソース2極性ビット */
LOGCONBbits.S2BPOL = PWM_DRV_LOGCON_SOURCE_POL_NORMAL;
/* PWMコンビネーションロジックBソース1極性ビット */
LOGCONBbits.S1BPOL = PWM_DRV_LOGCON_SOURCE_POL_NORMAL;
/* PWMコンビネーションロジックAソース2選択ビット */
LOGCONBbits.PWMS2B = PWM_DRV_LOGCON_SOURCE_PWM2L;
/* PWMコンビネーションロジックAソース1選択ビット */
LOGCONBbits.PWMS1B = PWM_DRV_LOGCON_SOURCE_PWM1L;
/*------------------------------------------------------------------------*/
/* PCI電流制御レジスタHの設定*/
/*------------------------------------------------------------------------*/
PG2CLPCIH = 0x0300;
PG3CLPCIH = 0x0300;
PG1CLPCIH = 0x0300;
/*------------------------------------------------------------------------*/
/* PWMの有効化*/
/*------------------------------------------------------------------------*/
PG1CONLbits.ON = 1u;
PG2CONLbits.ON = 1u;
PG3CONLbits.ON = 1u;
/*------------------------------------------------------------------------*/
/* メインルーチン*/
/*------------------------------------------------------------------------*/
while(1)
{
}
}
結果
(fig.5)(fig.6)のように、PWM1(ch1,2)とPWM2(ch3,4)の出力がPWM3(ch5,6)に出力されている事が確認できます。(画像ではCh0~Ch5に相当)
但しPWM3のパルスの幅が毎回異なっています。電源アプリケーションなどではこの現象が困る場合が有ると思います。


この現象はPWM1とPWM2の周期が同期していない事に起因します。
PWM1の周期(PG1PER)とPWM2の周期(MPERに同期)は以下のように整数倍となっているので、同期しそうですが、
MPER = 5000;
PG1PER = 500;
実はPWM周期(FPWM)は以下の通りPWMクロックを周期設定値+1で割った値になります。

つまり以下の通り記述するとPWM周期が整数倍になる為、同期する事になります。
MPER = 4999;
PG1PER = 499;
これ以外にも、PWM2の立ち上がりタイミングでPWM1の周期をリセットする方法も有りますが、それは次回説明したいと思います。
/*******************************************************************************
MPLAB Harmony Application Source File
Company:
Microchip Technology Inc.
File Name:
app.c
Summary:
This file contains the source code for the MPLAB Harmony application.
Description:
This file contains the source code for the MPLAB Harmony application. It
implements the logic of the application's state machine and it may call
API routines of other MPLAB Harmony modules in the system, such as drivers,
system services, and middleware. However, it does not call any of the
system interfaces (such as the "Initialize" and "Tasks" functions) of any of
the modules in the system or make any assumptions about when those functions
are called. That is the responsibility of the configuration-specific system
files.
*******************************************************************************/
// DOM-IGNORE-BEGIN
/*******************************************************************************
* Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries.
*
* Subject to your compliance with these terms, you may use Microchip software
* and any derivatives exclusively with Microchip products. It is your
* responsibility to comply with third party license terms applicable to your
* use of third party software (including open source software) that may
* accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*******************************************************************************/
// DOM-IGNORE-END
// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************
#include "app.h"
// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************
uint8_t CACHE_ALIGN switchPromptUSB[] = "\r\nPUSH BUTTON PRESSED";
uint8_t CACHE_ALIGN cdcReadBuffer[APP_READ_BUFFER_SIZE];
uint8_t CACHE_ALIGN cdcWriteBuffer[APP_READ_BUFFER_SIZE];
// *****************************************************************************
/* Application Data
Summary:
Holds application data
Description:
This structure holds the application's data.
Remarks:
This structure should be initialized by the APP_Initialize function.
Application strings and buffers are be defined outside this structure.
*/
APP_DATA appData;
// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************
/*******************************************************
* USB CDC Device Events - Application Event Handler
*******************************************************/
USB_DEVICE_CDC_EVENT_RESPONSE APP_USBDeviceCDCEventHandler
(
USB_DEVICE_CDC_INDEX index,
USB_DEVICE_CDC_EVENT event,
void * pData,
uintptr_t userData
)
{
APP_DATA * appDataObject;
USB_CDC_CONTROL_LINE_STATE * controlLineStateData;
USB_DEVICE_CDC_EVENT_DATA_READ_COMPLETE * eventDataRead;
appDataObject = (APP_DATA *)userData;
switch(event)
{
case USB_DEVICE_CDC_EVENT_GET_LINE_CODING:
/* This means the host wants to know the current line
* coding. This is a control transfer request. Use the
* USB_DEVICE_ControlSend() function to send the data to
* host. */
USB_DEVICE_ControlSend(appDataObject->deviceHandle,
&appDataObject->getLineCodingData, sizeof(USB_CDC_LINE_CODING));
break;
case USB_DEVICE_CDC_EVENT_SET_LINE_CODING:
/* This means the host wants to set the line coding.
* This is a control transfer request. Use the
* USB_DEVICE_ControlReceive() function to receive the
* data from the host */
USB_DEVICE_ControlReceive(appDataObject->deviceHandle,
&appDataObject->setLineCodingData, sizeof(USB_CDC_LINE_CODING));
break;
case USB_DEVICE_CDC_EVENT_SET_CONTROL_LINE_STATE:
/* This means the host is setting the control line state.
* Read the control line state. We will accept this request
* for now. */
controlLineStateData = (USB_CDC_CONTROL_LINE_STATE *)pData;
appDataObject->controlLineStateData.dtr = controlLineStateData->dtr;
appDataObject->controlLineStateData.carrier = controlLineStateData->carrier;
USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
break;
case USB_DEVICE_CDC_EVENT_SEND_BREAK:
/* This means that the host is requesting that a break of the
* specified duration be sent. Read the break duration */
appDataObject->breakData = ((USB_DEVICE_CDC_EVENT_DATA_SEND_BREAK *)pData)->breakDuration;
/* Complete the control transfer by sending a ZLP */
USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
break;
case USB_DEVICE_CDC_EVENT_READ_COMPLETE:
/* This means that the host has sent some data*/
eventDataRead = (USB_DEVICE_CDC_EVENT_DATA_READ_COMPLETE *)pData;
if(eventDataRead->status != USB_DEVICE_CDC_RESULT_ERROR)
{
appDataObject->isReadComplete = true;
appDataObject->numBytesRead = eventDataRead->length;
}
break;
case USB_DEVICE_CDC_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:
/* The data stage of the last control transfer is
* complete. For now we accept all the data */
USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
break;
case USB_DEVICE_CDC_EVENT_CONTROL_TRANSFER_DATA_SENT:
/* This means the GET LINE CODING function data is valid. We don't
* do much with this data in this demo. */
break;
case USB_DEVICE_CDC_EVENT_WRITE_COMPLETE:
/* This means that the data write got completed. We can schedule
* the next read. */
appDataObject->isWriteComplete = true;
break;
default:
break;
}
return USB_DEVICE_CDC_EVENT_RESPONSE_NONE;
}
/***********************************************
* Application USB Device Layer Event Handler.
***********************************************/
void APP_USBDeviceEventHandler
(
USB_DEVICE_EVENT event,
void * eventData,
uintptr_t context
)
{
USB_DEVICE_EVENT_DATA_CONFIGURED *configuredEventData;
switch(event)
{
case USB_DEVICE_EVENT_SOF:
/* This event is used for switch debounce. This flag is reset
* by the switch process routine. */
appData.sofEventHasOccurred = true;
break;
case USB_DEVICE_EVENT_RESET:
/* Update LED to show reset state */
LED_Off();
appData.isConfigured = false;
break;
case USB_DEVICE_EVENT_CONFIGURED:
/* Check the configuration. We only support configuration 1 */
configuredEventData = (USB_DEVICE_EVENT_DATA_CONFIGURED*)eventData;
if ( configuredEventData->configurationValue == 1)
{
/* Update LED to show configured state */
LED_On();
/* Register the CDC Device application event handler here.
* Note how the appData object pointer is passed as the
* user data */
USB_DEVICE_CDC_EventHandlerSet(USB_DEVICE_CDC_INDEX_0, APP_USBDeviceCDCEventHandler, (uintptr_t)&appData);
/* Mark that the device is now configured */
appData.isConfigured = true;
}
break;
case USB_DEVICE_EVENT_POWER_DETECTED:
/* VBUS was detected. We can attach the device */
USB_DEVICE_Attach(appData.deviceHandle);
break;
case USB_DEVICE_EVENT_POWER_REMOVED:
/* VBUS is not available. We can detach the device */
USB_DEVICE_Detach(appData.deviceHandle);
appData.isConfigured = false;
LED_Off();
break;
case USB_DEVICE_EVENT_SUSPENDED:
/* Switch LED to show suspended state */
LED_Off();
break;
case USB_DEVICE_EVENT_RESUMED:
case USB_DEVICE_EVENT_ERROR:
default:
break;
}
}
// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************
void APP_ProcessSwitchPress(void)
{
/* This function checks if the switch is pressed and then
* debounces the switch press*/
if(SWITCH_STATE_PRESSED == (SWITCH_Get()))
{
if(appData.ignoreSwitchPress)
{
/* This means the key press is in progress */
if(appData.sofEventHasOccurred)
{
/* A timer event has occurred. Update the debounce timer */
appData.switchDebounceTimer ++;
appData.sofEventHasOccurred = false;
if (USB_DEVICE_ActiveSpeedGet(appData.deviceHandle) == USB_SPEED_FULL)
{
appData.debounceCount = APP_USB_SWITCH_DEBOUNCE_COUNT_FS;
}
else if (USB_DEVICE_ActiveSpeedGet(appData.deviceHandle) == USB_SPEED_HIGH)
{
appData.debounceCount = APP_USB_SWITCH_DEBOUNCE_COUNT_HS;
}
if(appData.switchDebounceTimer == appData.debounceCount)
{
/* Indicate that we have valid switch press. The switch is
* pressed flag will be cleared by the application tasks
* routine. We should be ready for the next key press.*/
appData.isSwitchPressed = true;
appData.switchDebounceTimer = 0;
appData.ignoreSwitchPress = false;
}
}
}
else
{
/* We have a fresh key press */
appData.ignoreSwitchPress = true;
appData.switchDebounceTimer = 0;
}
}
else
{
/* No key press. Reset all the indicators. */
appData.ignoreSwitchPress = false;
appData.switchDebounceTimer = 0;
appData.sofEventHasOccurred = false;
}
}
/*****************************************************
* This function is called in every step of the
* application state machine.
*****************************************************/
bool APP_StateReset(void)
{
/* This function returns true if the device
* was reset */
bool retVal;
if(appData.isConfigured == false)
{
appData.state = APP_STATE_WAIT_FOR_CONFIGURATION;
appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
appData.isReadComplete = true;
appData.isWriteComplete = true;
retVal = true;
}
else
{
retVal = false;
}
return(retVal);
}
// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************
/*******************************************************************************
Function:
void APP_Initialize(void)
Remarks:
See prototype in app.h.
*/
void APP_Initialize(void)
{
/* Place the App state machine in its initial state. */
appData.state = APP_STATE_INIT;
/* Device Layer Handle */
appData.deviceHandle = USB_DEVICE_HANDLE_INVALID ;
/* Device configured status */
appData.isConfigured = false;
/* Initial get line coding state */
appData.getLineCodingData.dwDTERate = 9600;
appData.getLineCodingData.bParityType = 0;
appData.getLineCodingData.bCharFormat= 0;
appData.getLineCodingData.bDataBits = 8;
/* Read Transfer Handle */
appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
/* Write Transfer Handle */
appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
/* Initialize the read complete flag */
appData.isReadComplete = true;
/*Initialize the write complete flag*/
appData.isWriteComplete = true;
/* Initialize Ignore switch flag */
appData.ignoreSwitchPress = false;
/* Reset the switch debounce counter */
appData.switchDebounceTimer = 0;
/* Reset other flags */
appData.sofEventHasOccurred = false;
/* To know status of Switch */
appData.isSwitchPressed = false;
/* Set up the read buffer */
appData.cdcReadBuffer = &cdcReadBuffer[0];
/* Set up the read buffer */
appData.cdcWriteBuffer = &cdcWriteBuffer[0];
}
/******************************************************************************
Function:
void APP_Tasks(void)
Remarks:
See prototype in app.h.
*/
#if 0
void APP_Tasks(void)
{
/* Update the application state machine based
* on the current state */
int i;
switch(appData.state)
{
case APP_STATE_INIT:
/* Open the device layer */
appData.deviceHandle = USB_DEVICE_Open( USB_DEVICE_INDEX_0, DRV_IO_INTENT_READWRITE );
if(appData.deviceHandle != USB_DEVICE_HANDLE_INVALID)
{
/* Register a callback with device layer to get event notification (for end point 0) */
USB_DEVICE_EventHandlerSet(appData.deviceHandle, APP_USBDeviceEventHandler, 0);
appData.state = APP_STATE_WAIT_FOR_CONFIGURATION;
}
else
{
/* The Device Layer is not ready to be opened. We should try
* again later. */
}
break;
case APP_STATE_WAIT_FOR_CONFIGURATION:
/* Check if the device was configured */
if(appData.isConfigured)
{
/* If the device is configured then lets start reading */
appData.state = APP_STATE_SCHEDULE_READ;
}
break;
case APP_STATE_SCHEDULE_READ:
if(APP_StateReset())
{
break;
}
/* If a read is complete, then schedule a read
* else wait for the current read to complete */
appData.state = APP_STATE_WAIT_FOR_READ_COMPLETE;
if(appData.isReadComplete == true)
{
appData.isReadComplete = false;
appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
USB_DEVICE_CDC_Read (USB_DEVICE_CDC_INDEX_0,
&appData.readTransferHandle, appData.cdcReadBuffer,
APP_READ_BUFFER_SIZE);
if(appData.readTransferHandle == USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID)
{
appData.state = APP_STATE_ERROR;
break;
}
}
break;
case APP_STATE_WAIT_FOR_READ_COMPLETE:
case APP_STATE_CHECK_SWITCH_PRESSED:
if(APP_StateReset())
{
break;
}
APP_ProcessSwitchPress();
/* Check if a character was received or a switch was pressed.
* The isReadComplete flag gets updated in the CDC event handler. */
if(appData.isReadComplete || appData.isSwitchPressed)
{
appData.state = APP_STATE_SCHEDULE_WRITE;
}
break;
case APP_STATE_SCHEDULE_WRITE:
if(APP_StateReset())
{
break;
}
/* Setup the write */
appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
appData.isWriteComplete = false;
appData.state = APP_STATE_WAIT_FOR_WRITE_COMPLETE;
if(appData.isSwitchPressed)
{
/* If the switch was pressed, then send the switch prompt*/
appData.isSwitchPressed = false;
USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0,
&appData.writeTransferHandle, switchPromptUSB, sizeof(switchPromptUSB),
USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);
}
else
{
/* Else echo each received character by adding 1 */
for(i = 0; i < appData.numBytesRead; i++)
{
if((appData.cdcReadBuffer[i] != 0x0A) && (appData.cdcReadBuffer[i] != 0x0D))
{
appData.cdcWriteBuffer[i] = appData.cdcReadBuffer[i] + 1;
}
}
USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0,
&appData.writeTransferHandle,
appData.cdcWriteBuffer, appData.numBytesRead,
USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);
}
break;
case APP_STATE_WAIT_FOR_WRITE_COMPLETE:
if(APP_StateReset())
{
break;
}
/* Check if a character was sent. The isWriteComplete
* flag gets updated in the CDC event handler */
if(appData.isWriteComplete == true)
{
appData.state = APP_STATE_SCHEDULE_READ;
}
break;
case APP_STATE_ERROR:
default:
break;
}
}
#endif
#if 0
void APP_Tasks(void)
{
/* Update the application state machine based
* on the current state */
int i;
switch(appData.state)
{
case APP_STATE_INIT:
LATEbits.LATE0 = 0;
LATEbits.LATE1 = 1;
/* Open the device layer */
appData.deviceHandle = USB_DEVICE_Open( USB_DEVICE_INDEX_0, DRV_IO_INTENT_READWRITE );
if(appData.deviceHandle != USB_DEVICE_HANDLE_INVALID)
{
/* Register a callback with device layer to get event notification (for end point 0) */
USB_DEVICE_EventHandlerSet(appData.deviceHandle, APP_USBDeviceEventHandler, 0);
appData.state = APP_STATE_WAIT_FOR_CONFIGURATION;
}
else
{
/* The Device Layer is not ready to be opened. We should try
* again later. */
}
break;
case APP_STATE_WAIT_FOR_CONFIGURATION:
/* Check if the device was configured */
if(appData.isConfigured)
{
/* If the device is configured then lets start reading */
appData.state = APP_STATE_SCHEDULE_READ;
}
break;
case APP_STATE_SCHEDULE_READ:
LATEbits.LATE0 = 0;
LATEbits.LATE1 = 1;
if(APP_StateReset())
{
break;
}
/* If a read is complete, then schedule a read
* else wait for the current read to complete */
appData.state = APP_STATE_WAIT_FOR_READ_COMPLETE;
if(appData.isReadComplete == true)
{
appData.isReadComplete = false;
appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
USB_DEVICE_CDC_Read (USB_DEVICE_CDC_INDEX_0,
&appData.readTransferHandle, appData.cdcReadBuffer,
APP_READ_BUFFER_SIZE);
if(appData.readTransferHandle == USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID)
{
appData.state = APP_STATE_ERROR;
break;
}
}
break;
case APP_STATE_WAIT_FOR_READ_COMPLETE:
if(APP_StateReset())
{
break;
}
/* Check if a character was received or a switch was pressed.
* The isReadComplete flag gets updated in the CDC event handler. */
if(appData.isReadComplete )
{
appData.state = APP_STATE_SCHEDULE_WRITE;
}
break;
case APP_STATE_SCHEDULE_WRITE:
if(APP_StateReset())
{
break;
}
/* Setup the write */
appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
appData.isWriteComplete = false;
appData.state = APP_STATE_WAIT_FOR_WRITE_COMPLETE;
if(appData.isSwitchPressed)
{
/* If the switch was pressed, then send the switch prompt*/
appData.isSwitchPressed = false;
USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0,
&appData.writeTransferHandle, switchPromptUSB, sizeof(switchPromptUSB),
USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);
}
else
{
/* Else echo each received character by adding 1 */
for(i = 0; i < appData.numBytesRead; i++)
{
// if((appData.cdcReadBuffer[i] != 0x0A) && (appData.cdcReadBuffer[i] != 0x0D))
// {
appData.cdcWriteBuffer[i] = appData.cdcReadBuffer[i] + 1;
// }
}
USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0,
&appData.writeTransferHandle,
appData.cdcWriteBuffer, appData.numBytesRead,
USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);
}
break;
case APP_STATE_WAIT_FOR_WRITE_COMPLETE:
if(APP_StateReset())
{
break;
}
/* Check if a character was sent. The isWriteComplete
* flag gets updated in the CDC event handler */
if(appData.isWriteComplete == true)
{
appData.state = APP_STATE_SCHEDULE_READ;
}
break;
case APP_STATE_ERROR:
default:
LATEbits.LATE0 = 1;
LATEbits.LATE1 = 0;
break;
}
}
#endif
#if 1
void APP_Tasks(void)
{
/* Update the application state machine based
* on the current state */
int i,ascc;
// hoge
switch(appData.state)
{
case APP_STATE_INIT:
LATEbits.LATE0 = 0;
LATEbits.LATE1 = 1;
/* Open the device layer */
appData.deviceHandle = USB_DEVICE_Open( USB_DEVICE_INDEX_0, DRV_IO_INTENT_READWRITE );
if(appData.deviceHandle != USB_DEVICE_HANDLE_INVALID)
{
/* Register a callback with device layer to get event notification (for end point 0) */
USB_DEVICE_EventHandlerSet(appData.deviceHandle, APP_USBDeviceEventHandler, 0);
appData.state = APP_STATE_WAIT_FOR_CONFIGURATION;
}
else
{
/* The Device Layer is not ready to be opened. We should try
* again later. */
}
ascc = 21;
for(i = 0; i < 4095; i++)
{
// if((appData.cdcReadBuffer[i] != 0x0A) && (appData.cdcReadBuffer[i] != 0x0D))
// {
appData.cdcWriteBuffer[i] = ascc++;
if (ascc > 126) ascc = 21;
}
break;
case APP_STATE_WAIT_FOR_CONFIGURATION:
/* Check if the device was configured */
if(appData.isConfigured)
{
/* If the device is configured then lets start reading */
appData.state = APP_STATE_SCHEDULE_WRITE;
}
break;
case APP_STATE_SCHEDULE_READ:
LATEbits.LATE0 = 0;
LATEbits.LATE1 = 1;
if(APP_StateReset())
{
break;
}
/* If a read is complete, then schedule a read
* else wait for the current read to complete */
if(appData.isReadComplete == true)
{
appData.isReadComplete = false;
appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
USB_DEVICE_CDC_Read (USB_DEVICE_CDC_INDEX_0,
&appData.readTransferHandle, appData.cdcReadBuffer,
APP_READ_BUFFER_SIZE);
if(appData.readTransferHandle == USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID)
{
appData.state = APP_STATE_ERROR;
break;
}
}
appData.state = APP_STATE_SCHEDULE_WRITE;
break;
case APP_STATE_WAIT_FOR_READ_COMPLETE:
if(APP_StateReset())
{
break;
}
/* Check if a character was received or a switch was pressed.
* The isReadComplete flag gets updated in the CDC event handler. */
if(appData.isReadComplete )
{
appData.state = APP_STATE_SCHEDULE_WRITE;
}
break;
case APP_STATE_SCHEDULE_WRITE:
if(APP_StateReset())
{
break;
}
/* Setup the write */
appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
appData.isWriteComplete = false;
appData.state = APP_STATE_WAIT_FOR_WRITE_COMPLETE;
USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0,
&appData.writeTransferHandle,
appData.cdcWriteBuffer, 512,
USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);
break;
case APP_STATE_WAIT_FOR_WRITE_COMPLETE:
if(APP_StateReset())
{
break;
}
/* Check if a character was sent. The isWriteComplete
* flag gets updated in the CDC event handler */
if(appData.isWriteComplete == true)
{
appData.state = APP_STATE_SCHEDULE_WRITE;
}
break;
case APP_STATE_ERROR:
default:
LATEbits.LATE0 = 1;
LATEbits.LATE1 = 0;
break;
}
}
/*******************************************************************************
End of File
*/
#endif
/*******************************************************************************
* Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries.
*
* Subject to your compliance with these terms, you may use Microchip software
* and any derivatives exclusively with Microchip products. It is your
* responsibility to comply with third party license terms applicable to your
* use of third party software (including open source software) that may
* accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*******************************************************************************/
/*******************************************************************************
Main Source File
Company:
Microchip Technology Inc.
File Name:
main.c
Summary:
This file contains the "main" function for a project.
Description:
This file contains the "main" function for a project. The
"main" function calls the "SYS_Initialize" function to initialize the state
machines of all modules in the system
*******************************************************************************/
// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************
#include <stddef.h> // Defines NULL
#include <stdbool.h> // Defines true
#include <stdlib.h> // Defines EXIT_FAILURE
#include "definitions.h" // SYS function prototypes
#include "app.h"
// *****************************************************************************
// *****************************************************************************
// Section: Main Entry Point
// *****************************************************************************
// *****************************************************************************
#define ConvertToPhysicalAddress(a) ((uint32_t)KVA_TO_PA(a))
#define ConvertToVirtualAddress(a) PA_TO_KVA1(a)
extern __inline__ unsigned int __attribute__((always_inline)) virt_to_phys(volatile const void* p)
//extern __inline__ unsigned int __attribute__((always_inline)) virt_to_phys(volatile unsigned int* p)
{
return (int)p<0?((int)p&0x1fffffffL):(unsigned int)((unsigned char*)p+0x40000000L);
}
/**************************************************************************/
/*PIC32MZにおいてUSBフルスピードのスループットを調べる*/
/*送信単位 512Byte = 10MByte/sec*/
/*送信単位 1024Byte = 20MByte/sec*/
/**************************************************************************/
int main ( void )
{
/* Initialize all modules */
SYS_Initialize ( NULL );
while ( true )
{
/* Maintain state machines of all polled MPLAB Harmony modules. */
SYS_Tasks ( );
//fatfs_test1();
}
/* Execution should not come here during normal operation */
return ( EXIT_FAILURE );
}
/*******************************************************************************
End of File
*/


コメント